自动化立体仓库 - WCS系统
#
18516761980
2022-06-08 556c49e32f5f38cca479eb2a12025712b2f1807b
#
12个文件已添加
2个文件已修改
1345 ■■■■ 已修改文件
src/main/java/com/zy/core/netty/AbstractInboundHandler.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/netty/HandlerInitializer.java 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/netty/OnlineServer.java 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/netty/cache/ChannelAttrKey.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/netty/cache/ChannelCache.java 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/netty/constant/Constant.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/netty/domain/ChPackage.java 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/netty/handle/PackageServerHandler.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/netty/handle/ProtectorHandler.java 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/netty/handle/ProtocolDecoder.java 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/netty/handle/ProtocolEncoder.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/netty/properties/TcpProperties.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/thread/SiemensDevpThread.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/render.js 624 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/netty/AbstractInboundHandler.java
New file
@@ -0,0 +1,34 @@
package com.zy.core.netty;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;
/**
 * netty handler增强器
 * 设计模式: 适配器模式
 * Created by vincent on 2019-04-02
 */
public abstract class AbstractInboundHandler<T> extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object obj) throws Exception {
        @SuppressWarnings("unchecked")
        T t = (T) obj;
        if (channelRead0(ctx, t)) {
            ctx.fireChannelRead(t);
        } else  {
            // 管道中断,fireChannelRead未执行,需要手动释放堆外内存
            if (obj instanceof ByteBuf) {
                ReferenceCountUtil.release(obj);
            }
//            if (obj instanceof GBPackage){
//                GBPackage pac = (GBPackage) obj;
//                ReferenceCountUtil.release(pac.getSourceBuff());
//            }
        }
    }
    protected abstract boolean channelRead0(ChannelHandlerContext ctx, T t) throws Exception;
}
src/main/java/com/zy/core/netty/HandlerInitializer.java
New file
@@ -0,0 +1,77 @@
package com.zy.core.netty;
import com.core.common.SnowflakeIdWorker;
import com.zy.core.netty.cache.ChannelAttrKey;
import com.zy.core.netty.handle.PackageServerHandler;
import com.zy.core.netty.handle.ProtectorHandler;
import com.zy.core.netty.handle.ProtocolDecoder;
import com.zy.core.netty.handle.ProtocolEncoder;
import com.zy.core.netty.properties.TcpProperties;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.Attribute;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
 * handler管道
 * 控制所有netty handler流向
 * 待完成: 动态管理handler
 * Created by vincent on 2019-04-02
 */
@Component
@ChannelHandler.Sharable
public class HandlerInitializer extends ChannelInitializer<Channel> {
    @Autowired
    private SnowflakeIdWorker snowflakeIdWorker;
    @Autowired
    private TcpProperties tcpProperties;
    @Autowired
    private ProtocolEncoder protocolEncoder;
    @Autowired
    private PackageServerHandler packageServerHandler;
    @Autowired
    private ProtectorHandler protectorHandler;
    /**
     * Set some channel handlers on channel pipeline
     */
    @Override
    protected void initChannel(Channel channel) {
        channel.pipeline()
                // 心跳
                .addLast(new IdleStateHandler(tcpProperties.getHeartSeconds(), 0, 0))
                // 编码器
                .addLast(protocolEncoder)
                // 解码器
                .addLast(new ProtocolDecoder(snowflakeIdWorker))
                // 校验码处理器
//                .addLast(validateHandler)
                // 认证处理器
//                .addLast(vehAuthHandler)
                // 业务处理器
                .addLast(packageServerHandler)
                // 通道保护器
                .addLast(protectorHandler);
        // Channel局部变量,相当于线程的ThreadLocal
//        initAttrTrack(channel);
    }
    /**
     *  Init channel attr track
     */
    private void initAttrTrack(Channel channel){
        Attribute<Map<String, Object>> coolTrackAttr = channel.attr(ChannelAttrKey.DATA_MAP_ATTR);
        Map<String, Object> trackMap = new HashMap<>();
        coolTrackAttr.setIfAbsent(trackMap);
    }
}
src/main/java/com/zy/core/netty/OnlineServer.java
New file
@@ -0,0 +1,92 @@
package com.zy.core.netty;
import com.zy.core.netty.properties.TcpProperties;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.ResourceLeakDetector;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
/**
 * TCP/IP协议端口
 * Netty Server 引导类
 * @author Vincent
 */
@Slf4j
@Component
public class OnlineServer {
    private final HandlerInitializer handlerInitializer;
    private final TcpProperties tcpProperties;
    private Channel channel;
    private ServerBootstrap bootstrap;
    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;
    @Autowired
    public OnlineServer(TcpProperties tcpProperties, HandlerInitializer handlerInitializer) { ;
        this.tcpProperties = tcpProperties;
        this.handlerInitializer = handlerInitializer;
    }
    {
        bootstrap = new ServerBootstrap();
        bossGroup = new NioEventLoopGroup(1);
        workerGroup = new NioEventLoopGroup();
    }
    /**
     *  tcp server init
     */
    @PostConstruct
    public void serverStart() throws Exception {
        // 开启大端模式
//        CStruct.reverse = false;
        bootstrap.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(handlerInitializer)
                .option(ChannelOption.SO_BACKLOG, tcpProperties.getBacklog())
                .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                .childOption(ChannelOption.SO_KEEPALIVE, tcpProperties.isKeepAlive())
                .childOption(ChannelOption.SO_SNDBUF, tcpProperties.getSndbuf())
                .childOption(ChannelOption.SO_RCVBUF, tcpProperties.getRcvbuf());
        ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.ADVANCED);
        log.info("TCP server started successfully, port:{}", tcpProperties.getPort());
        channel = bootstrap.bind(tcpProperties.getPort()).sync().channel();
    }
    /**
     * tcp server stop
     */
    @PreDestroy
    public void destroy() {
        if (channel != null && channel.isActive()) {
            channel.close();
        }
        if (bossGroup != null) {
            bossGroup.shutdownGracefully();
        }
        if (workerGroup != null) {
            workerGroup.shutdownGracefully();
        }
        log.info("TCP server stopped successfully, port: {}", tcpProperties.getPort());
    }
}
src/main/java/com/zy/core/netty/cache/ChannelAttrKey.java
New file
@@ -0,0 +1,18 @@
package com.zy.core.netty.cache;
import io.netty.util.AttributeKey;
import java.util.Map;
/**
 * Channel局部变量缓存 ==>> 线程安全
 * Created by vincent on 2019-04-02
 */
public final class ChannelAttrKey {
    private static String CHANNEL_ATTR_KEY_VC_TRACK = "channel.attr.vc.track";
    public static AttributeKey<Map<String, Object>> DATA_MAP_ATTR = AttributeKey.newInstance(CHANNEL_ATTR_KEY_VC_TRACK);
}
src/main/java/com/zy/core/netty/cache/ChannelCache.java
New file
@@ -0,0 +1,63 @@
package com.zy.core.netty.cache;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
 * Channel缓存 ==>> {
 *                   key: uuid
 *                   value: Channel
 *                 }
 * Created by vincent on 2019-04-02
 */
@Slf4j
@RestController
public class ChannelCache {
    private static Map<String, Channel> channelGroup = new ConcurrentHashMap<>();
    public static void setChannel(String uuid, Channel channel){
        // todo 缓存标记 ===>> 分布式系统
//        String hostName = SystemProperties.HOST_NAME;
        if (getChannel(uuid) == channel){
            return;
        }
        removeChannel(uuid);
        channelGroup.put(uuid, channel);
    }
    public static Channel getChannel(String uuid){
        return channelGroup.get(uuid);
    }
    public static void removeChannel(String uuid) {
        Channel channel = getChannel(uuid);
        if (null == channel){
            return;
        }
        channelGroup.remove(uuid);
        channel.close();
    }
    public static String removeChannel(Channel channel){
        String key = null;
        for (Map.Entry<String, Channel> entry : channelGroup.entrySet()){
            if (entry.getValue() == channel){
                key = entry.getKey();
                break;
            }
        }
        if (null != key){
            channelGroup.remove(key);
            return key;
        }
        return null;
    }
}
src/main/java/com/zy/core/netty/constant/Constant.java
New file
@@ -0,0 +1,15 @@
package com.zy.core.netty.constant;
import java.nio.charset.Charset;
/**
 * 配置常量
 * Created by vincent on 2019-04-03
 */
public class Constant {
    public static final String SYMBOL = "##";
    public static final Charset CHARSET_GBK = Charset.forName("GBK");
}
src/main/java/com/zy/core/netty/domain/ChPackage.java
New file
@@ -0,0 +1,72 @@
package com.zy.core.netty.domain;
import io.netty.buffer.ByteBuf;
import lombok.Data;
/**
 * 报文模型
 * Created by vincent on 2019-04-03
 */
@Data
public class ChPackage {
    /**
     * 唯一编码
     */
    private String uuid;
    /**
     * 源数据包缓冲区(引用)
     */
    private ByteBuf sourceBuff;
    /**
     * 原始消息对应的16进制字符串
     */
    private String sourceHexStr;
    /**
     * 请求体
     */
    private ByteBuf content;
    private byte[] bytes;
    private String ascii;
    private String ip;
    /**
     * 消息的校正码
     */
    private byte validCode;
    /**
     * 是否为校验异常包
     */
    private boolean errorPac;
    public static ChPackage valueOfEmpty(String uuid, String ip) {
        ChPackage chPackage = new ChPackage();
        chPackage.setUuid(uuid);
        chPackage.setIp(ip);
        return chPackage;
    }
//    public ByteBuf convert(ByteBuf byteBuf){
//        byteBuf.writeBytes(this.getHeader().getStartSymbol().getBytes(Constant.CHARSET_GBK))
//                .writeByte(this.getHeader().getCommandMark().getCode())
//                .writeByte(this.getHeader().getAckMark().getCode())
//                .writeBytes(this.getHeader().getUniqueNo().getBytes())
//                .writeByte(this.getHeader().getEncryptType().getCode())
//                .writeShort(this.getHeader().getContentLength())
//                .writeBytes(this.getBody().getContent())
//                .writeByte(this.getValidCode());
//        // 计算并设置校验码
//        this.setValidCode(ValidUtil.caculateValidByteFromBuff(byteBuf));
//        byteBuf.resetReaderIndex();
//        byteBuf.writerIndex(byteBuf.readableBytes() - 1).writeByte(this.getValidCode());
//        return byteBuf;
//    }
}
src/main/java/com/zy/core/netty/handle/PackageServerHandler.java
New file
@@ -0,0 +1,67 @@
package com.zy.core.netty.handle;
import com.core.common.Cools;
import com.zy.core.Slave;
import com.zy.core.cache.SlaveConnection;
import com.zy.core.enums.SlaveType;
import com.zy.core.netty.AbstractInboundHandler;
import com.zy.core.netty.cache.ChannelCache;
import com.zy.core.netty.domain.ChPackage;
import com.zy.core.netty.properties.TcpProperties;
import com.zy.core.properties.SlaveProperties;
import com.zy.core.thread.BarcodeThread;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
 * 国标业务处理handler
 * Created by vincent on 2019-04-02
 */
@Slf4j
@Component
@ChannelHandler.Sharable
public class PackageServerHandler extends AbstractInboundHandler<ChPackage> {
    @Autowired
    private SlaveProperties slaveProperties;
    @Autowired
    private TcpProperties tcpProperties;
    @Override
    protected boolean channelRead0(ChannelHandlerContext ctx, ChPackage pac) {
//        log.info("读码器【IP:{}】 上行数据 ===>> {}", pac.getIp(), pac.getAscii());
//        //扫码上传数据格式必须2个#开头,如:##12345678
//        String msg = pac.getAscii().replaceAll("#", "");
//        if(!Cools.isEmpty(msg) && msg.length()>=tcpProperties.getBarcodeLen()){
//            msg = msg.substring(0,tcpProperties.getBarcodeLen());
//
//            for (Slave slave : slaveProperties.getBarcode()) {
//                if (slave.getIp().equals(pac.getIp())) {
//                    BarcodeThread barcodeThread = (BarcodeThread) SlaveConnection.get(SlaveType.Barcode, slave.getId());
//                    if (barcodeThread == null) { continue; }
//                    barcodeThread.setBarcode(msg);
//                    break;
//                }
//            }
//        }
        return true;
    }
    /**
     * 数据下行
     */
    public static void write(ChPackage chPackage){
        String uuid = chPackage.getUuid();
        Channel channel = ChannelCache.getChannel(uuid);
        if (null == channel){
            log.warn("通道uuid={} 不在线", uuid);
            return;
        }
        channel.writeAndFlush(chPackage);
    }
}
src/main/java/com/zy/core/netty/handle/ProtectorHandler.java
New file
@@ -0,0 +1,69 @@
package com.zy.core.netty.handle;
import com.core.common.Cools;
import com.zy.core.netty.AbstractInboundHandler;
import com.zy.core.netty.cache.ChannelCache;
import com.zy.core.netty.domain.ChPackage;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
 * 通道维护handler
 * Created by vincent on 2019-04-11
 */
@Slf4j
@Component("protectorHandler")
@ChannelHandler.Sharable
public class ProtectorHandler extends AbstractInboundHandler<ChPackage> {
    @Override
    protected boolean channelRead0(ChannelHandlerContext ctx, ChPackage pac) throws Exception {
        // jvm堆外内存需要手动释放
//        ReferenceCountUtil.release(pac.getSourceBuff());
        return true;
    }
    /**
     * 空闲剔除
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent e = (IdleStateEvent) evt;
            if (IdleState.READER_IDLE == e.state()) {
                String uuid = ChannelCache.removeChannel(ctx.channel());
                ctx.close();
                if (!Cools.isEmpty(uuid)){
                    log.info("uuid={} 空闲剔除", uuid);
                }
            }
        }
    }
    /**
     * 断开连接
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        String uuid = ChannelCache.removeChannel(ctx.channel());
        ctx.close();
        if (!Cools.isEmpty(uuid)){
            log.info("通道 uuid={} 失去连接", uuid);
        }
    }
    /**
     * 管道异常
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ChannelCache.removeChannel(ctx.channel());
        ctx.close();
    }
}
src/main/java/com/zy/core/netty/handle/ProtocolDecoder.java
New file
@@ -0,0 +1,113 @@
package com.zy.core.netty.handle;
import com.core.common.SnowflakeIdWorker;
import com.zy.core.netty.constant.Constant;
import com.zy.core.netty.domain.ChPackage;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.List;
/**
 * Created by vincent on 2019-04-10
 */
public class ProtocolDecoder extends ByteToMessageDecoder {
    private final SnowflakeIdWorker snowflakeIdWorker;
    public ProtocolDecoder(SnowflakeIdWorker snowflakeIdWorker){
        this.snowflakeIdWorker = snowflakeIdWorker;
    }
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> list) throws Exception {
        int startMark = indexOfStartMark(in);
        if (startMark == -1){
            return;
        }
        // 去除无用前缀报文
        if (startMark != 0){
            in.readerIndex(startMark);
            in.discardReadBytes();
        }
        // 生成和初始化消息包装类
        String ip = ((InetSocketAddress) ctx.channel().remoteAddress()).getAddress().getHostAddress();
        ChPackage pac = ChPackage.valueOfEmpty(String.valueOf(snowflakeIdWorker.nextId()), ip);
        pac.setSourceBuff(in);
        // 解析
        list.add(analyzeProtocol(pac));
    }
    public ChPackage analyzeProtocol(ChPackage pac){
        ByteBuf byteBuf = pac.getSourceBuff();
        // 备份缓冲区
        ByteBuf body = byteBuf.duplicate();
        if (null != body && body.readableBytes() >= 0) {
            pac.setContent(body);
        } else {
            return null;
        }
        // 字节数组
        body.resetReaderIndex();
        byte[] bytes = new byte[body.readableBytes()];
        body.readBytes(bytes);
        body.resetReaderIndex();
        pac.setBytes(bytes);
        // ascii
        if (bytes.length > 0) {
            pac.setAscii(new String(pac.getBytes(), StandardCharsets.US_ASCII));
        }
        // 备份字符串
        if (null != pac.getSourceBuff() && null == pac.getSourceHexStr()) {
            pac.getSourceBuff().resetReaderIndex();
            pac.setSourceHexStr(ByteBufUtil.hexDump(pac.getSourceBuff()));
            pac.getSourceBuff().resetReaderIndex();
        }
        byteBuf.skipBytes(byteBuf.readableBytes());
//        pac.getSourceBuff().readByte();
        return pac;
    }
    // 获取标识位下标
    private int indexOfStartMark(ByteBuf inputBuffer){
        int length = inputBuffer.writerIndex();
        // 报文长度至少大于2
        if (length < 2) {
            return -1;
        }
        int readerIndex = inputBuffer.readerIndex();
        for(int i = readerIndex; i < length - 1; i ++) {
            byte b1 = inputBuffer.getByte(i);
            // "#" = b1
            if (0x23 == b1) {
                // "#" = b2
                if (i + 1 <= length && 0x23 == inputBuffer.getByte(i + 1)) {
                    return i;
                }
            }
        }
        return -1;
    }
    private String byte2Str(ByteBuf buf, int len) {
        byte[] bytes = new byte[len];
        buf.readBytes(bytes);
        return new String(bytes, Constant.CHARSET_GBK);
    }
}
src/main/java/com/zy/core/netty/handle/ProtocolEncoder.java
New file
@@ -0,0 +1,51 @@
package com.zy.core.netty.handle;
import com.zy.core.netty.domain.ChPackage;
import com.zy.core.netty.properties.TcpProperties;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
 * 国标编码器
 * 此解码器将会生成校验码
 * 处理方式: 异或和
 * Created by vincent on 2019-04-02
 */
@Slf4j
@Component
@ChannelHandler.Sharable
public class ProtocolEncoder extends MessageToByteEncoder<Object> {
    @Autowired
    private TcpProperties tcpProperties;
    @Override
    protected void encode(ChannelHandlerContext ctx, Object obj, ByteBuf out) {
        boolean upgradeLog = true;
        if (obj instanceof ByteBuf){
            out.writeBytes((ByteBuf) obj);
        } else if (obj instanceof byte[]) {
            out.writeBytes((byte[]) obj);
        } else if (obj instanceof ChPackage) {
        }
//        if (tcpProperties.isPrintPacLog() || upgradeLog){
//            log.info("uuid={} 下行 >>> {}", getVin(out), ByteBufUtil.hexDump(out));
//        }
    }
//    private String getVin(ByteBuf byteBuf){
//        byte[] bytes = new byte[PackagePart.UNIQUENO.getLen()];
//        byteBuf.markReaderIndex();
//        byteBuf.readerIndex(PackagePart.UNIQUENO.getStartIndex());
//        byteBuf.readBytes(bytes);
//        byteBuf.resetReaderIndex();
//        return RadixTools.bytesToStr(bytes);
//    }
}
src/main/java/com/zy/core/netty/properties/TcpProperties.java
New file
@@ -0,0 +1,45 @@
package com.zy.core.netty.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
 * vc系统配置
 * Created by luxiaotao on 2018/10/15
 */
@Data
@Configuration
@ConfigurationProperties(prefix = "tcp")
public class TcpProperties {
    public static String HOST_NAME;
    static {
        try {
            HOST_NAME = InetAddress.getLocalHost().getHostName();
        } catch (UnknownHostException e) {
            System.err.println("find hostname err");
        }
    }
    private int port;
    private int heartSeconds;
    private int backlog;
    private boolean keepAlive;
    private int sndbuf;
    private int rcvbuf;
    private boolean printPacLog;
    private int barcodeLen;
}
src/main/java/com/zy/core/thread/SiemensDevpThread.java
@@ -53,6 +53,10 @@
        add(120);add(121);add(122);add(123);add(124);add(125);add(126);add(127);add(128);add(129);
        add(130);add(131);add(132);add(133);add(134);add(135);add(136);
    }};
    @Autowired
    private SlaveProperties slaveProperties;
    /**
     * 条码数量
     */
@@ -174,6 +178,7 @@
        }
        Thread.sleep(200);
        barcodeSize = slaveProperties.getBarcode().size();
        OperateResultExOne<byte[]> result2 = siemensS7Net.Read("DB100.190",(short)(barcodeSize*8));
        if (result2.IsSuccess) {
            for (int i = 0; i < barcodeSize; i++) {
src/main/webapp/views/render.js
@@ -1,462 +1,554 @@
data = {
    "mapName": "HYLYWCS",
    "rackCount": 16,
    "crnCount": 4,
    "stbCount": 14,
    "hpPosition": 0,
    "mapName": "KLSWCS",
    "rackCount": 12,
    "crnCount": 3,
    "stbCount": 36,
    "hpPosition": 1,
    "minBayNo": 2,
    "floors": 1,
    "racks": [{
        "type": "rack",
        "id": "rack16",
        "top": 650,
        "left": 412,
        "width": 1046,
        "height": 24,
        "minBayNo": 2,
        "maxBayNo": 24
    }, {
        "type": "rack",
        "id": "rack15",
        "top": 624,
        "left": 412,
        "width": 1046,
        "height": 24,
        "minBayNo": 2,
        "maxBayNo": 24
    }, {
        "type": "rack",
        "id": "rack14",
        "top": 569,
        "left": 412,
        "width": 1046,
        "height": 24,
        "minBayNo": 2,
        "maxBayNo": 24
    }, {
        "type": "rack",
        "id": "rack13",
        "top": 543,
        "left": 412,
        "width": 1046,
        "height": 24,
        "minBayNo": 2,
        "maxBayNo": 24
    }, {
        "type": "rack",
        "id": "rack12",
        "top": 484,
        "left": 412,
        "width": 1099,
        "height": 24,
        "top": 646,
        "left": 324,
        "width": 887,
        "height": 30,
        "minBayNo": 2,
        "maxBayNo": 64
        "maxBayNo": 52
    }, {
        "type": "rack",
        "id": "rack11",
        "top": 458,
        "left": 412,
        "width": 1099,
        "height": 24,
        "top": 613,
        "left": 324,
        "width": 887,
        "height": 30,
        "minBayNo": 2,
        "maxBayNo": 64
        "maxBayNo": 52
    }, {
        "type": "rack",
        "id": "rack10",
        "top": 399,
        "left": 412,
        "width": 1099,
        "height": 24,
        "top": 516,
        "left": 324,
        "width": 887,
        "height": 30,
        "minBayNo": 2,
        "maxBayNo": 64
        "maxBayNo": 52
    }, {
        "type": "rack",
        "id": "rack9",
        "top": 373,
        "left": 412,
        "width": 1099,
        "height": 24,
        "top": 483,
        "left": 324,
        "width": 887,
        "height": 30,
        "minBayNo": 2,
        "maxBayNo": 64
        "maxBayNo": 52
    }, {
        "type": "rack",
        "id": "rack8",
        "top": 344,
        "left": 405,
        "width": 979,
        "height": 24,
        "top": 451,
        "left": 324,
        "width": 887,
        "height": 30,
        "minBayNo": 2,
        "maxBayNo": 16
        "maxBayNo": 52
    }, {
        "type": "rack",
        "id": "rack7",
        "top": 318,
        "left": 405,
        "width": 979,
        "height": 24,
        "top": 418,
        "left": 324,
        "width": 887,
        "height": 30,
        "minBayNo": 2,
        "maxBayNo": 16
        "maxBayNo": 52
    }, {
        "type": "rack",
        "id": "rack6",
        "top": 263,
        "left": 405,
        "width": 979,
        "height": 24,
        "top": 323,
        "left": 324,
        "width": 887,
        "height": 30,
        "minBayNo": 2,
        "maxBayNo": 16
        "maxBayNo": 52
    }, {
        "type": "rack",
        "id": "rack5",
        "top": 237,
        "left": 405,
        "width": 979,
        "height": 24,
        "top": 290,
        "left": 324,
        "width": 887,
        "height": 30,
        "minBayNo": 2,
        "maxBayNo": 16
        "maxBayNo": 52
    }, {
        "type": "rack",
        "id": "rack3",
        "top": 180,
        "left": 357,
        "width": 1027,
        "height": 24,
        "top": 225,
        "left": 188,
        "width": 1023,
        "height": 30,
        "minBayNo": 2,
        "maxBayNo": 31
        "maxBayNo": 60
    }, {
        "type": "rack",
        "id": "rack1",
        "top": 97,
        "left": 357,
        "width": 1027,
        "height": 24,
        "left": 188,
        "width": 1023,
        "height": 30,
        "minBayNo": 2,
        "maxBayNo": 31
        "maxBayNo": 60
    }, {
        "type": "rack",
        "id": "rack4",
        "top": 207,
        "left": 357,
        "width": 1027,
        "height": 24,
        "top": 257,
        "left": 188,
        "width": 1023,
        "height": 30,
        "minBayNo": 2,
        "maxBayNo": 31
        "maxBayNo": 60
    }, {
        "type": "rack",
        "id": "rack2",
        "top": 123,
        "left": 357,
        "width": 1027,
        "height": 24,
        "top": 129,
        "left": 188,
        "width": 1023,
        "height": 30,
        "minBayNo": 2,
        "maxBayNo": 31
        "maxBayNo": 60
    }],
    "rackDescs": [{
        "type": "rackDescs",
        "id": "lb_desc16",
        "text": "#16",
        "top": 651,
        "left": 1471,
        "width": 41,
        "height": 23
    }, {
        "type": "rackDescs",
        "id": "lb_desc15",
        "text": "#15",
        "top": 626,
        "left": 1472,
        "width": 40,
        "height": 23
    }, {
        "type": "rackDescs",
        "id": "lb_desc14",
        "text": "#14",
        "top": 565,
        "left": 1469,
        "width": 41,
        "height": 23
    }, {
        "type": "rackDescs",
        "id": "lb_desc13",
        "text": "#13",
        "top": 541,
        "left": 1472,
        "width": 40,
        "height": 23
    }, {
        "type": "rackDescs",
        "id": "lb_desc12",
        "text": "#12",
        "top": 485,
        "left": 1517,
        "width": 41,
        "height": 23
        "top": 646,
        "left": 260,
        "width": 47,
        "height": 27
    }, {
        "type": "rackDescs",
        "id": "lb_desc11",
        "text": "#11",
        "top": 460,
        "left": 1518,
        "width": 38,
        "height": 23
        "top": 618,
        "left": 260,
        "width": 44,
        "height": 27
    }, {
        "type": "rackDescs",
        "id": "lb_desc10",
        "text": "#10",
        "top": 399,
        "left": 1515,
        "width": 42,
        "height": 23
        "top": 516,
        "left": 257,
        "width": 49,
        "height": 27
    }, {
        "type": "rackDescs",
        "id": "lb_desc9",
        "text": "#9",
        "top": 375,
        "left": 1518,
        "width": 33,
        "height": 23
        "top": 488,
        "left": 257,
        "width": 38,
        "height": 27
    }, {
        "type": "rackDescs",
        "id": "lb_desc8",
        "text": "#8",
        "top": 349,
        "left": 1389,
        "width": 33,
        "height": 23
        "top": 449,
        "left": 260,
        "width": 39,
        "height": 27
    }, {
        "type": "rackDescs",
        "id": "lb_desc7",
        "text": "#7",
        "top": 321,
        "left": 1389,
        "width": 32,
        "height": 23
        "top": 421,
        "left": 260,
        "width": 37,
        "height": 27
    }, {
        "type": "rackDescs",
        "id": "lb_desc6",
        "text": "#6",
        "top": 264,
        "left": 1387,
        "width": 33,
        "height": 23
        "top": 327,
        "left": 260,
        "width": 38,
        "height": 27
    }, {
        "type": "rackDescs",
        "id": "lb_desc5",
        "text": "#5",
        "top": 235,
        "left": 1388,
        "width": 32,
        "height": 23
        "top": 291,
        "left": 261,
        "width": 38,
        "height": 27
    }, {
        "type": "rackDescs",
        "id": "lb_desc4",
        "text": "#4",
        "top": 206,
        "left": 1388,
        "width": 33,
        "height": 23
        "top": 253,
        "left": 145,
        "width": 38,
        "height": 27
    }, {
        "type": "rackDescs",
        "id": "lb_desc3",
        "text": "#3",
        "top": 179,
        "left": 1389,
        "width": 32,
        "height": 23
        "top": 225,
        "left": 145,
        "width": 38,
        "height": 27
    }, {
        "type": "rackDescs",
        "id": "lb_desc2",
        "text": "#2",
        "top": 123,
        "left": 1389,
        "width": 33,
        "height": 23
        "top": 128,
        "left": 145,
        "width": 38,
        "height": 27
    }, {
        "type": "rackDescs",
        "id": "lb_desc1",
        "text": "#1",
        "top": 95,
        "left": 1389,
        "width": 30,
        "height": 23
        "top": 100,
        "left": 145,
        "width": 35,
        "height": 27
    }],
    "crns": [{
        "type": "crane",
        "id": "crn-4",
        "text": "4",
        "top": 597,
        "left": 500,
        "width": 93,
        "height": 22
    }, {
        "type": "track",
        "id": "lb_track4",
        "text": "",
        "top": 606,
        "left": 366,
        "width": 1150,
        "height": 2
    }, {
        "type": "crane",
        "id": "crn-1",
        "text": "1",
        "top": 153,
        "left": 500,
        "top": 184,
        "left": 777,
        "width": 93,
        "height": 22
    }, {
        "type": "crane",
        "id": "crn-2",
        "text": "2",
        "top": 291,
        "left": 500,
        "top": 378,
        "left": 777,
        "width": 93,
        "height": 22
    }, {
        "type": "crane",
        "id": "crn-3",
        "text": "3",
        "top": 428,
        "left": 500,
        "top": 572,
        "left": 777,
        "width": 93,
        "height": 22
    }, {
        "type": "track",
        "id": "lb_track2",
        "text": "",
        "top": 300,
        "left": 359,
        "width": 1066,
        "top": 387,
        "left": 146,
        "width": 1112,
        "height": 2
    }, {
        "type": "track",
        "id": "lb_track3",
        "text": "",
        "top": 438,
        "left": 359,
        "width": 1200,
        "top": 582,
        "left": 146,
        "width": 1112,
        "height": 2
    }, {
        "type": "track",
        "id": "lb_track1",
        "text": "",
        "top": 164,
        "left": 315,
        "top": 195,
        "left": 146,
        "width": 1112,
        "height": 2
    }],
    "stns": [{
        "type": "stn",
        "id": "site-132",
        "text": "132",
        "top": 547,
        "left": 1399,
        "width": 60,
        "height": 63
    }, {
        "type": "stn",
        "id": "site-126",
        "text": "126",
        "top": 450,
        "left": 1461,
        "width": 60,
        "height": 63
    }, {
        "type": "stn",
        "id": "site-125",
        "text": "125",
        "top": 450,
        "left": 1399,
        "width": 60,
        "height": 63
    }, {
        "type": "stn",
        "id": "site-119",
        "text": "119",
        "top": 353,
        "left": 1461,
        "width": 60,
        "height": 63
    }, {
        "type": "stn",
        "id": "site-118",
        "text": "118",
        "top": 353,
        "left": 1399,
        "width": 60,
        "height": 63
    }, {
        "type": "stn",
        "id": "site-136",
        "text": "136",
        "top": 611,
        "left": 1461,
        "width": 120,
        "height": 30
    }, {
        "type": "stn",
        "id": "site-135",
        "text": "135",
        "top": 611,
        "left": 1399,
        "width": 60,
        "height": 30
    }, {
        "type": "stn",
        "id": "site-134",
        "text": "134",
        "top": 611,
        "left": 1337,
        "width": 60,
        "height": 30
    }, {
        "type": "stn",
        "id": "site-133",
        "text": "133",
        "top": 611,
        "left": 1215,
        "width": 120,
        "height": 30
    }, {
        "type": "stn",
        "id": "site-130",
        "text": "130",
        "top": 515,
        "left": 1461,
        "width": 60,
        "height": 30
    }, {
        "type": "stn",
        "id": "site-129",
        "text": "129",
        "top": 515,
        "left": 1399,
        "width": 60,
        "height": 30
    }, {
        "type": "stn",
        "id": "site-128",
        "text": "128",
        "top": 515,
        "left": 1337,
        "width": 60,
        "height": 30
    }, {
        "type": "stn",
        "id": "site-127",
        "text": "127",
        "top": 515,
        "left": 1215,
        "width": 120,
        "height": 30
    }, {
        "type": "stn",
        "id": "site-131",
        "text": "131",
        "top": 515,
        "left": 1522,
        "width": 60,
        "height": 30
    }, {
        "type": "stn",
        "id": "site-123",
        "text": "123",
        "top": 418,
        "left": 1461,
        "width": 60,
        "height": 30
    }, {
        "type": "stn",
        "id": "site-122",
        "text": "122",
        "top": 418,
        "left": 1399,
        "width": 60,
        "height": 30
    }, {
        "type": "stn",
        "id": "site-121",
        "text": "121",
        "top": 418,
        "left": 1337,
        "width": 60,
        "height": 30
    }, {
        "type": "stn",
        "id": "site-120",
        "text": "120",
        "top": 418,
        "left": 1215,
        "width": 120,
        "height": 30
    }, {
        "type": "stn",
        "id": "site-124",
        "text": "124",
        "top": 418,
        "left": 1522,
        "width": 60,
        "height": 30
    }, {
        "type": "stn",
        "id": "site-112",
        "text": "112",
        "top": 458,
        "left": 311,
        "width": 100,
        "height": 24
        "top": 256,
        "left": 1461,
        "width": 60,
        "height": 63
    }, {
        "type": "stn",
        "id": "site-111",
        "text": "111",
        "top": 458,
        "left": 209,
        "width": 100,
        "height": 24
        "top": 256,
        "left": 1399,
        "width": 60,
        "height": 63
    }, {
        "type": "stn",
        "id": "site-116",
        "text": "116",
        "top": 321,
        "left": 1461,
        "width": 60,
        "height": 30
    }, {
        "type": "stn",
        "id": "site-115",
        "text": "115",
        "top": 321,
        "left": 1399,
        "width": 60,
        "height": 30
    }, {
        "type": "stn",
        "id": "site-114",
        "text": "114",
        "top": 568,
        "left": 311,
        "width": 100,
        "height": 24
        "top": 321,
        "left": 1337,
        "width": 60,
        "height": 30
    }, {
        "type": "stn",
        "id": "site-113",
        "text": "113",
        "top": 568,
        "left": 209,
        "width": 100,
        "height": 24
        "top": 321,
        "left": 1215,
        "width": 120,
        "height": 30
    }, {
        "type": "stn",
        "id": "site-117",
        "text": "117",
        "top": 321,
        "left": 1522,
        "width": 60,
        "height": 30
    }, {
        "type": "stn",
        "id": "site-105",
        "text": "105",
        "top": 262,
        "left": 201,
        "width": 100,
        "height": 24
        "top": 159,
        "left": 1399,
        "width": 60,
        "height": 63
    }, {
        "type": "stn",
        "id": "site-109",
        "text": "109",
        "top": 399,
        "left": 208,
        "width": 100,
        "height": 24
        "top": 224,
        "left": 1461,
        "width": 60,
        "height": 30
    }, {
        "type": "stn",
        "id": "site-108",
        "text": "108",
        "top": 318,
        "left": 303,
        "width": 100,
        "height": 24
        "top": 224,
        "left": 1399,
        "width": 60,
        "height": 30
    }, {
        "type": "stn",
        "id": "site-107",
        "text": "107",
        "top": 318,
        "left": 201,
        "width": 100,
        "height": 24
        "top": 224,
        "left": 1337,
        "width": 60,
        "height": 30
    }, {
        "type": "stn",
        "id": "site-106",
        "text": "106",
        "top": 262,
        "left": 303,
        "width": 100,
        "height": 24
        "top": 224,
        "left": 1215,
        "width": 120,
        "height": 30
    }, {
        "type": "stn",
        "id": "site-104",
        "text": "104",
        "top": 180,
        "left": 255,
        "width": 100,
        "height": 24
        "top": 128,
        "left": 1461,
        "width": 120,
        "height": 30
    }, {
        "type": "stn",
        "id": "site-103",
        "text": "103",
        "top": 180,
        "left": 153,
        "width": 100,
        "height": 24
        "top": 128,
        "left": 1399,
        "width": 60,
        "height": 30
    }, {
        "type": "stn",
        "id": "site-102",
        "text": "102",
        "top": 122,
        "left": 255,
        "width": 100,
        "height": 24
        "top": 128,
        "left": 1337,
        "width": 60,
        "height": 30
    }, {
        "type": "stn",
        "id": "site-101",
        "text": "101",
        "top": 122,
        "left": 153,
        "width": 100,
        "height": 24
        "top": 128,
        "left": 1215,
        "width": 120,
        "height": 30
    }, {
        "type": "stn",
        "id": "site-110",
        "text": "110",
        "top": 399,
        "left": 310,
        "width": 100,
        "height": 24
        "top": 224,
        "left": 1522,
        "width": 60,
        "height": 30
    }]
}