hjp 4 місяців тому
батько
коміт
6adb5e2d3c

+ 12 - 0
pom.xml

@@ -77,6 +77,18 @@
             <artifactId>fastjson2</artifactId>
             <artifactId>fastjson2</artifactId>
             <version>${fastjson.version}</version>
             <version>${fastjson.version}</version>
         </dependency>
         </dependency>
+
+        <dependency>
+            <groupId>com.infiniteautomation</groupId>
+            <artifactId>modbus4j</artifactId>
+            <version>3.0.3</version>
+        </dependency>
+
+        <!-- webSocket 开始-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-websocket</artifactId>
+        </dependency>
     </dependencies>
     </dependencies>
 
 
     <build>
     <build>

+ 0 - 2
src/main/java/com/jg/JgApplication.java

@@ -42,8 +42,6 @@ public class JgApplication
                 "Doc: \t\t\t\thttp://" + ip + ":" + port + "/doc.html\n\t" +
                 "Doc: \t\t\t\thttp://" + ip + ":" + port + "/doc.html\n\t" +
                 "swagger-ui: \t\thttp://" + ip + ":" + port + "/swagger-ui/index.html\n\t" +
                 "swagger-ui: \t\thttp://" + ip + ":" + port + "/swagger-ui/index.html\n\t" +
                 "----------------------------------------------------------");
                 "----------------------------------------------------------");
-
-
     }
     }
 
 
 
 

+ 44 - 0
src/main/java/com/jg/common/ApiController.java

@@ -0,0 +1,44 @@
+package com.jg.common;
+
+/**
+ * <p>
+ *     REST API 通用控制器
+ * </p>
+ *
+ * @author lxp
+ * @version V1.0
+ * @since 2022/7/20  0:04
+ */
+public class ApiController {
+
+    /**
+     * 请求成功
+     *
+     * @param data 数据内容
+     * @param <T>  对象泛型
+     * @return ignore
+     */
+    protected <T> Result<T> ok(T data) {
+        return Result.ok(data);
+    }
+
+    /**
+     * 请求失败
+     *
+     * @param msg 提示内容
+     * @return ignore
+     */
+    protected <T> Result<T> failed(String msg) {
+        return Result.failed(msg);
+    }
+
+    /**
+     * 请求失败
+     *
+     * @param errorCode 请求错误码
+     * @return ignore
+     */
+    protected <T> Result<T> failed(ErrorCode errorCode) {
+        return Result.failed(errorCode);
+    }
+}

+ 60 - 0
src/main/java/com/jg/common/ApiErrorCode.java

@@ -0,0 +1,60 @@
+package com.jg.common;
+
+import lombok.Getter;
+
+/**
+ * <p>
+ *     REST API 错误码
+ * </p>
+ *
+ * @author lxp
+ * @version V1.0
+ * @since 2022/7/19  23:53
+ */
+@Getter
+public enum ApiErrorCode implements ErrorCode {
+    /**
+     * 操作失败
+     */
+    FAILED(-1, "操作失败"),
+    /**
+     * 执行成功
+     */
+    SUCCESS(200, "请求成功"),
+    /**
+     * 客户端引起的--请求参数格式错误
+     */
+    ERR_BAD_REQUEST(400, "请求参数格式错误!"),
+    /**
+     * (未授权) 请求要求身份验证。
+     */
+    UNAUTHORIZED(401, "权限不足!"),
+    /**
+     * 客户端引起的--JWT--过期
+     */
+    ERR_TOKEN_EXPIRED(401, "Token已过期!"),
+    /**
+     * 客户端引起的--JWT--数据无效
+     */
+    ERR_TOKEN_MALFORMED(401, "Token解析错误!"),
+    /**
+     * 服务端引起的--插入数据错误
+     */
+    ERR_INSERT(500, "插入数据错误"),
+    /**
+     * 服务端引起的--更新数据错误
+     */
+    ERR_UPDATE(500, "更新数据错误"),
+    /**
+     * 服务端引起的--服务器内部错误
+     */
+    ERR_INTERNAL_SERVER_ERROR(500, "服务器内部错误");
+
+    private final long code;
+    private final String message;
+
+    ApiErrorCode(final long code, final String message) {
+        this.code = code;
+        this.message = message;
+    }
+}

+ 49 - 0
src/main/java/com/jg/common/ApiException.java

@@ -0,0 +1,49 @@
+package com.jg.common;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * <p>
+ *     REST API 请求异常类
+ * </p>
+ *
+ * @author lxp
+ * @version V1.0
+ * @since 2022/7/20  0:01
+ */
+@Setter
+@Getter
+public class ApiException extends RuntimeException {
+
+    /**
+     * serialVersionUID
+     */
+    private static final long serialVersionUID = -5885155226898287919L;
+
+    /**
+     * 错误码
+     */
+    private ErrorCode errorCode;
+
+    public ApiException(ErrorCode errorCode) {
+        super(errorCode.getMessage());
+        this.errorCode = errorCode;
+    }
+
+    public ApiException(String message) {
+        super(message);
+    }
+
+    public ApiException(Throwable cause) {
+        super(cause);
+    }
+
+    public ApiException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public ErrorCode getErrorCode() {
+        return errorCode;
+    }
+}

+ 23 - 0
src/main/java/com/jg/common/ErrorCode.java

@@ -0,0 +1,23 @@
+package com.jg.common;
+
+/**
+ * <p>
+ *     REST API 错误码接口
+ * </p>
+ *
+ * @author lxp
+ * @version V1.0
+ * @since 2022/7/19  23:53
+ */
+public interface ErrorCode {
+
+    /**
+     * 错误编码 -1、失败 0、成功
+     */
+    long getCode();
+
+    /**
+     * 错误描述
+     */
+    String getMessage();
+}

+ 83 - 0
src/main/java/com/jg/common/Result.java

@@ -0,0 +1,83 @@
+package com.jg.common;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Optional;
+
+/**
+ * <p>
+ *     全局统一返回结果
+ * </p>
+ *
+ * @author lxp
+ * @version V1.0
+ * @since 2022/7/19  23:43
+ */
+@Data
+@ApiModel(value = "全局统一返回结果")
+public class Result<T> implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "业务错误码")
+    private long code;
+
+    @ApiModelProperty(value = "返回数据")
+    private T data;
+
+    @ApiModelProperty(value = "返回消息")
+    private String message;
+
+    private Result(){
+        // to do nothing
+    }
+
+    public Result(ErrorCode errorCode) {
+        errorCode = Optional.ofNullable(errorCode).orElse(ApiErrorCode.FAILED);
+        this.code = errorCode.getCode();
+        this.message = errorCode.getMessage();
+    }
+
+    public static <T> Result<T> ok() {
+        return restResult(null, ApiErrorCode.SUCCESS);
+    }
+
+    public static <T> Result<T> ok(T data) {
+        ApiErrorCode aec = ApiErrorCode.SUCCESS;
+        if (data instanceof Boolean && Boolean.FALSE.equals(data)) {
+            aec = ApiErrorCode.FAILED;
+        }
+        return restResult(data, aec);
+    }
+
+    public static <T> Result<T> failed(String message) {
+        return restResult(null, ApiErrorCode.FAILED.getCode(), message);
+    }
+
+    public static <T> Result<T> failed(ErrorCode errorCode) {
+        return restResult(null, errorCode);
+    }
+
+    public static <T> Result<T> failed(long errorCode, String message) {
+        return restResult(null, errorCode, message);
+    }
+
+    public static <T> Result<T> failed(ErrorCode errorCode, String message) {
+        return restResult(null, errorCode.getCode(), message);
+    }
+
+    public static <T> Result<T> restResult(T data, ErrorCode errorCode) {
+        return restResult(data, errorCode.getCode(), errorCode.getMessage());
+    }
+
+    private static <T> Result<T> restResult(T data, long code, String message) {
+        Result<T> apiResult = new Result<>();
+        apiResult.setCode(code);
+        apiResult.setData(data);
+        apiResult.setMessage(message);
+        return apiResult;
+    }
+}

+ 22 - 0
src/main/java/com/jg/common/ValueType.java

@@ -0,0 +1,22 @@
+package com.jg.common;
+
+/**
+ * <p>
+ * </p>
+ *
+ * @author lxp
+ * @version V1.0
+ * @since 2023/1/2  10:53
+ */
+public interface ValueType {
+
+    String BYTE = "byte";
+    String SHORT = "short";
+    String INT = "int";
+    String LONG = "long";
+    String FLOAT = "float";
+    String DOUBLE = "double";
+    String BOOLEAN = "boolean";
+    String STRING = "string";
+    String ENUM = "enum";
+}

+ 22 - 0
src/main/java/com/jg/config/WebSocketConfig.java

@@ -0,0 +1,22 @@
+package com.jg.config;
+
+/**
+ * 开启WebSocket支持
+ * @author zyl
+ * @version 1.0
+ * @date 2023/7/12 9:00
+ */
+
+import org.springframework.boot.web.servlet.ServletRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.socket.server.standard.ServerEndpointExporter;
+
+@Configuration
+public class WebSocketConfig {
+
+    @Bean
+    public ServerEndpointExporter serverEndpointExporter() {
+        return new ServerEndpointExporter(); // 自动注册 @ServerEndpoint 注解的 WebSocket 端点
+    }
+}

+ 27 - 0
src/main/java/com/jg/controller/ModbusController.java

@@ -0,0 +1,27 @@
+package com.jg.controller;
+
+import com.jg.service.ModBusService;
+import com.jg.common.Result;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@Slf4j
+@Api(tags = "采集标签控制器")
+@RestController
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
+public class ModbusController {
+    @Autowired
+    private ModBusService modBusService;
+
+    @GetMapping("/all")
+    @ApiOperation("查询所有采集标签")
+    public Result<Object> all() {
+        modBusService.startCollect();
+        return Result.ok();
+    }
+}

+ 12 - 0
src/main/java/com/jg/service/ModBusService.java

@@ -0,0 +1,12 @@
+package com.jg.service;
+
+import java.util.List;
+
+public interface ModBusService {
+
+    /**
+     * 开始采集数据
+     */
+    void startCollect();
+
+}

+ 190 - 0
src/main/java/com/jg/service/impl/ModBusServiceImpl.java

@@ -0,0 +1,190 @@
+package com.jg.service.impl;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONArray;
+import com.jg.common.ValueType;
+import com.jg.service.ModBusService;
+import com.jg.util.ModBusUtil;
+import com.jg.util.WebSocketServer;
+import com.jg.vo.ShowVo;
+import com.jg.vo.TagVo;
+import com.serotonin.modbus4j.BatchRead;
+import com.serotonin.modbus4j.BatchResults;
+import com.serotonin.modbus4j.ModbusMaster;
+import com.serotonin.modbus4j.code.DataType;
+import com.serotonin.modbus4j.locator.BaseLocator;
+import jdk.nashorn.internal.ir.annotations.Reference;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.event.ApplicationReadyEvent;
+import org.springframework.context.event.EventListener;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.*;
+
+@Slf4j
+@Service
+public class ModBusServiceImpl implements ModBusService {
+
+    private static final Map<Long, ModbusMaster> MASTER_MAP = new HashMap<>(64);
+
+    @Value("${modbus.host}")
+    private String host;
+
+    @Value("${modbus.port}")
+    private Integer port;
+
+    @Reference
+    private WebSocketServer webSocketServer;
+
+    /**
+     * 创建ModBusTCP连接
+     */
+    @EventListener(ApplicationReadyEvent.class)
+    private void createConn() {
+        // 创建ModBus连接, 存入MASTER_MAP
+//        List<CollectModuleInfo> collectModuleInfoList = collectModuleInfoService.findCurrent();
+//        log.info("[查询采集模块列表]: {}", collectModuleInfoList);
+//        if (!CollectionUtils.isEmpty(collectModuleInfoList)) {
+//            for (CollectModuleInfo collectModuleInfo : collectModuleInfoList) {
+//                Long collectModuleInfoId = collectModuleInfo.getId();
+//                MODULE_INFO_MAP.put(collectModuleInfoId, collectModuleInfo);
+//                // 循环创建ModBus连接
+//                ModbusMaster modbusMaster = MASTER_MAP.get(collectModuleInfoId);
+//                if (null == modbusMaster) {
+//                    // 创建ModBus连接, 存入Map, key: 采集模块id, value: ModBus连接
+//                    modbusMaster = ModBusUtil.createMaster(collectModuleInfo);
+//                    MASTER_MAP.put(collectModuleInfoId, modbusMaster);
+//                }
+//            }
+//        } else {
+////            throw new BizException("连接失败! 没有查询到ModBus模块信息!");
+//        }
+//        log.warn("[开始连接采集模块]: {}", JSON.toJSONString(collectModuleInfoList));
+        ModbusMaster master = ModBusUtil.createMaster(host, port);
+        MASTER_MAP.put(1l, master);
+    }
+
+    @Scheduled(fixedRate = 1000)
+    private void readTagsValue(){
+//        ArrayList<ShowVo> showVos = new ArrayList<>();
+        JSONArray array = new JSONArray();
+        String s = "";
+        try {
+            s = new String(Files.readAllBytes(Paths.get(ClassLoader.getSystemResource("tag.json").toURI())), StandardCharsets.UTF_8);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        List<TagVo> tagVos = JSON.parseArray(s, TagVo.class);
+        BatchRead<String> batch = new BatchRead<>();
+        for (TagVo tagVo: tagVos){
+            Integer slaveId = tagVo.getSlaveId();
+            Integer functionCode = tagVo.getFunctionCode();
+            int offset = tagVo.getOffset();
+            String tag = tagVo.getTag();
+            String dataType = tagVo.getDataType();
+            switch (functionCode) {
+                case 1:
+                    batch.addLocator(tag, BaseLocator.coilStatus(slaveId, offset));
+                    break;
+                case 2:
+                    batch.addLocator(tag, BaseLocator.inputStatus(slaveId, offset));
+                    break;
+                case 3:
+                    batch.addLocator(tag, BaseLocator.holdingRegister(slaveId, offset, getValueType(dataType)));
+                    break;
+                case 4:
+                    batch.addLocator(tag, BaseLocator.inputRegister(slaveId, offset, getValueType(dataType)));
+                    break;
+                default:
+                    break;
+            }
+        }
+        batch.setContiguousRequests(false);
+        ModbusMaster modbusMaster = MASTER_MAP.get(1l);
+        try {
+            if (!modbusMaster.isInitialized()) {
+                modbusMaster.init();
+            }
+            modbusMaster.setTimeout(500);
+            BatchResults<String> results = modbusMaster.send(batch);
+            for (TagVo tagVo: tagVos){
+//                log.info("采集中文: {}, 值: {}", tagVo.getDesc(), results.getValue(tagVo.getTag()));
+                Object value = results.getValue(tagVo.getTag());
+                BigDecimal bigDecimalValue = convertToBigDecimal(value);
+                ShowVo showVo = new ShowVo();
+                showVo.setName(tagVo.getDesc());
+                showVo.setValue(bigDecimalValue);
+                showVo.setUnit(tagVo.getUnit());
+//                showVos.add(showVo);
+                array.add(showVo);
+            }
+            webSocketServer.sendInfo(array.toString(), "push");
+            modbusMaster.destroy();
+        } catch (Exception e) {
+            log.error("采集模块Id: {}, 读取失败: {}", 1l, e.getMessage());
+        }
+    }
+
+    /**
+     * 获取数据类型
+     * 说明:此处可根据实际项目情况进行拓展
+     * 1.swap 交换
+     * 2.大端/小端,默认是大端
+     * 3.拓展其他数据类型
+     *
+     * @param type Value Type
+     * @return Modbus Data Type
+     */
+    public static int getValueType(String type) {
+        switch (type.toLowerCase()) {
+            case ValueType.LONG:
+                return DataType.FOUR_BYTE_INT_SIGNED;
+            case ValueType.FLOAT:
+                return DataType.FOUR_BYTE_FLOAT;
+            case ValueType.DOUBLE:
+                return DataType.EIGHT_BYTE_FLOAT;
+            default:
+                return DataType.TWO_BYTE_INT_UNSIGNED;
+        }
+    }
+
+    /**
+     * 将 Object 转换为 BigDecimal
+     **/
+    private static BigDecimal convertToBigDecimal(Object obj) {
+        // 处理 obj 为 null 的情况,返回 -1
+        if (obj == null) {
+            return BigDecimal.valueOf(-1);
+        }
+        if (obj instanceof BigDecimal) {
+            return (BigDecimal) obj;
+        } else if (obj instanceof Integer) {
+            return BigDecimal.valueOf((Integer) obj);
+        } else if (obj instanceof Double) {
+            return BigDecimal.valueOf((Double) obj);
+        } else if (obj instanceof String) {
+            return new BigDecimal((String) obj);
+        } else if (obj instanceof Float){
+            return BigDecimal.valueOf(((Float) obj).doubleValue());
+        } else if (obj instanceof Boolean) {
+            return BigDecimal.valueOf((Boolean) obj ? 1 : 0);
+        } else {
+            throw new IllegalArgumentException("Unsupported object type: " + obj.getClass());
+        }
+    }
+
+    @Override
+    public void startCollect() {
+        createConn();
+        readTagsValue();
+    }
+
+}

+ 50 - 0
src/main/java/com/jg/util/ModBusUtil.java

@@ -0,0 +1,50 @@
+package com.jg.util;
+
+
+import com.alibaba.fastjson2.JSON;
+import com.serotonin.modbus4j.ModbusFactory;
+import com.serotonin.modbus4j.ModbusMaster;
+import com.serotonin.modbus4j.ip.IpParameters;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * <p>
+ *     modbus读取工具类
+ * </p>
+ *
+ * @author lxp
+ * @version V1.0
+ * @since 2023/1/1  22:31
+ */
+@Slf4j
+public class ModBusUtil {
+
+    public static ModbusFactory modbusFactory;
+
+    static {
+        modbusFactory = new ModbusFactory();
+    }
+
+    /**
+     * 获取 Modbus Master
+     *
+     * @return ModBusMaster
+     */
+    public static ModbusMaster createMaster(String host, Integer port) {
+        try {
+            IpParameters params = new IpParameters();
+            params.setHost(host);
+            params.setPort(port);
+            //这个属性确定了协议帧是否是通过tcp封装的RTU结构,采用modbus tcp/ip时,要设为false,
+            // 采用modBus rtu over tcp/ip时,要设为true
+            params.setEncapsulated(false);
+            ModbusMaster master = modbusFactory.createTcpMaster(params, false);
+            master.setTimeout(4000);
+            master.setRetries(3);
+            return master;
+        } catch (Exception e) {
+            log.error("连接失败, Modbus Tcp Connection Info ModbusSlaveInfo: {}", JSON.toJSONString("collectModuleInfo"));
+            throw new RuntimeException(e);
+        }
+    }
+}

+ 143 - 0
src/main/java/com/jg/util/WebSocketServer.java

@@ -0,0 +1,143 @@
+package com.jg.util;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import javax.websocket.*;
+import javax.websocket.server.PathParam;
+import javax.websocket.server.ServerEndpoint;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+
+@Slf4j
+@ServerEndpoint("/websocket/{sid}")
+@Component
+public class WebSocketServer {
+    // 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
+    private static int onlineCount = 0;
+    //concurrent 包的线程安全 Set ,用来存放每个客户端对应的 MyWebSocket 对象。
+    private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();
+
+
+    // 与某个客户端的连接会话,需要通过它来给客户端发送数据
+    private Session session;
+
+    // 接收 sid
+    private String sid = "";
+
+    // 创建一个数组用来存放所有需要向客户端发送消息的窗口号
+    private static List<String> list = new ArrayList();
+
+    public static List<String> getList() {
+        return list;
+    }
+
+
+    /**
+     * 连接建立成功调用的方法
+     */
+    @OnOpen
+    public void onOpen(Session session, @PathParam("sid") String sid){
+        this.session = session;
+        this.sid = sid;
+        list.add(sid);
+        webSocketSet.add(this);
+        addOnlineCount();   //在线数加1
+                try {
+            sendMessage("WebSocket连接成功!");
+            if (!sid.equals("pictures")){
+                log.info("有新窗口开始监听:" + sid + ",当前在线人数为:" + getOnlineCount());
+            }
+        } catch (Exception e) {
+            log.error("websocket IO Exception");
+        }
+    }
+
+    /**
+     * 连接关闭调用的方法
+     */
+    @OnClose
+    public void onClose() {
+        webSocketSet.remove(this); // 从 set 中删除
+        list.remove(sid);
+
+        webSocketSet.remove(this); // 从 set 中删除
+        list.remove(sid);
+        subOnlineCount(); // 在线数减 1
+        if (!sid.equals("pictures")){
+            log.info(" 有一连接关闭,窗口为:" + sid + "!当前在线人数为 " + getOnlineCount());
+        }
+    }
+
+    /**
+     * 收到客户端消息后调用的方法
+     *
+     * @param message 客户端发送过来的消息
+     */
+    @OnMessage
+    public void onMessage(String message, Session session) {
+
+
+        /*log.info(" 收到来自窗口 " + sid + " 的信息 :" + message);
+
+        String returnMessage = "你刚才说:" + message;
+        try {
+            session.getBasicRemote().sendText(returnMessage);
+        } catch (IOException e) {
+            System.out.println("返回数据失败");
+        }*/
+    }
+
+    /**
+     * @param session
+     * @param error
+     */
+    @OnError
+    public void onError(Session session, Throwable error) {
+        log.error(" 发生错误 ");
+        error.printStackTrace();
+    }
+
+    /**
+     * 实现服务器主动推送
+     */
+    public void sendMessage(String message) throws IOException {
+        this.session.getBasicRemote().sendText(message);
+    }
+
+
+    /**
+     * 群发自定义消息
+     */
+    public static void sendInfo(String message, @PathParam("sid") String sid) throws IOException {
+//        log.info(" 推送消息到窗口 " + sid + " ,推送内容 :" + message);
+        for (WebSocketServer item : webSocketSet) {
+            try {
+                // 这里可以设定只推送给这个 sid 的,为 null 则全部推送
+                if (sid == null) {
+                    item.sendMessage(message);
+                } else if (item.sid.equals(sid)) {
+                    item.sendMessage(message);
+                }
+            } catch (IOException e) {
+                continue;
+            }
+        }
+    }
+
+    public static synchronized int getOnlineCount() {
+        return onlineCount;
+    }
+
+    public static synchronized void addOnlineCount() {
+        WebSocketServer.onlineCount++;
+    }
+
+    public static synchronized void subOnlineCount() {
+        WebSocketServer.onlineCount--;
+    }
+
+}

+ 19 - 0
src/main/java/com/jg/vo/ShowVo.java

@@ -0,0 +1,19 @@
+package com.jg.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class ShowVo {
+
+    public String name;
+
+    public BigDecimal value;
+
+    public String unit;
+}

+ 25 - 0
src/main/java/com/jg/vo/TagVo.java

@@ -0,0 +1,25 @@
+package com.jg.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class TagVo {
+
+    private int offset;
+
+    private int slaveId;
+
+    private int functionCode;
+
+    private String tag;
+
+    private String desc;
+
+    private String unit;
+
+    private String dataType;
+}

+ 3 - 0
src/main/resources/application-dev.yml

@@ -0,0 +1,3 @@
+modbus:
+  host: 192.168.0.100
+  port: 8234

+ 1 - 1
src/main/resources/application.yml

@@ -13,7 +13,7 @@ jg:
 # 开发环境配置
 # 开发环境配置
 server:
 server:
   # 服务器的HTTP端口,默认为8080
   # 服务器的HTTP端口,默认为8080
-  port: 9999
+  port: 6999
   servlet:
   servlet:
     # 应用的访问路径
     # 应用的访问路径
     context-path: /
     context-path: /

+ 20 - 0
src/main/resources/tag.json

@@ -0,0 +1,20 @@
+[
+  {
+    "offset": 0,
+    "slaveId": 1,
+    "functionCode": 3,
+    "tag": "1",
+    "desc": "温度",
+    "unit": "℃",
+    "dataType": "int"
+  },
+  {
+    "offset": 1,
+    "slaveId": 1,
+    "functionCode": 3,
+    "tag": "2",
+    "desc": "压力",
+    "unit": "Pa",
+    "dataType": "int"
+  }
+]