Bladeren bron

实时大屏摄像头播放部分优化,添加L2上料部分

wangxiaofei 1 maand geleden
bovenliggende
commit
053f7e6aeb
20 gewijzigde bestanden met toevoegingen van 536 en 288 verwijderingen
  1. 19 12
      taphole-admin/src/main/resources/application-test.yml
  2. 0 13
      taphole-camera/src/main/java/com.sckj.camera/model/bo/CameraBO.java
  3. 0 24
      taphole-camera/src/main/java/com.sckj.camera/service/CameraServiceImpl.java
  4. 32 0
      taphole-common/src/main/java/com/sckj/common/manager/TaskManager.java
  5. 4 0
      taphole-device/pom.xml
  6. 8 8
      taphole-device/src/main/java/com/sckj/device/controller/TCameraController.java
  7. 6 0
      taphole-device/src/main/java/com/sckj/device/entity/TCamera.java
  8. 0 71
      taphole-device/src/main/java/com/sckj/device/service/ITCameraService.java
  9. 111 38
      taphole-device/src/main/java/com/sckj/device/service/impl/TCameraServiceImpl.java
  10. 32 0
      taphole-device/src/main/java/com/sckj/device/validate/TCameraUpdateDTO.java
  11. 21 0
      taphole-device/src/main/java/com/sckj/device/vo/CameraDTO.java
  12. 2 2
      taphole-iron/pom.xml
  13. 18 58
      taphole-iron/src/main/java/com/sckj/iron/controller/TIronVisualScreenController.java
  14. 0 9
      taphole-iron/src/main/java/com/sckj/iron/dto/CameraDTO.java
  15. 85 0
      taphole-iron/src/main/java/com/sckj/iron/entity/TL2Material.java
  16. 13 0
      taphole-iron/src/main/java/com/sckj/iron/mapper/TL2MaterialMapper.java
  17. 38 0
      taphole-iron/src/main/java/com/sckj/iron/service/impl/TL2MaterialServiceImpl.java
  18. 77 49
      taphole-iron/src/main/java/com/sckj/iron/socketio/DeviceEventListener.java
  19. 57 0
      taphole-opc/src/main/java/com/sckj/opc/dto/L2Material.java
  20. 13 4
      taphole-opc/src/main/java/com/sckj/opc/opcua/L2DataServiceImpl.java

+ 19 - 12
taphole-admin/src/main/resources/application-test.yml

@@ -1,41 +1,48 @@
 # 项目配置
 like:
-  upload-directory: /home/xiaofei/uploads/taphole/ # 上传目录
+  upload-directory: D:/opt/camera/
 
 # 服务配置
 server:
-  port: 8080
+  port: 28080
   servlet:
     context-path: /
+
 # 框架配置
 spring:
   # 数据源配置
   datasource:
-    url: jdbc:mysql://mysql:3306/taphole?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false
+    url: jdbc:mysql://192.168.110.130:13306/taphole?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false
     type: com.alibaba.druid.pool.DruidDataSource # 数据源类型
     driver-class-name: com.mysql.jdbc.Driver # MySql的驱动
     username: root # 数据库账号
     password: root # 数据库密码
   # Redis配置
   redis:
-    host: redis   # Redis服务地址
-    port: 6379        # Redis端口
-#    password: sckj@1234        # Redis密码
-#    database: 5       # 数据库索引
+    host: 192.168.110.130   # Redis服务地址
+    port: 16379        # Redis端口
+    password:         # Redis密码
+    database: 5       # 数据库索引
+#    lettuce:
+#      pool:
+#        max-wait: 30000 # 连接池最大阻塞等待时间(使用负数表示没有限制,默认-1)
+#        max-active: 100 # 连接池最大连接数(使用负数表示没有限制,默认8)
+#        max-idle: 20    # 连接池中的最大空闲连接(默认8)
+#        min-idle: 0     # 连接池中的最小空闲连接(默认0)
 
 # Mybatis-plus配置 【是否开启SQL日志输出】
 #mybatis-plus:
 #    configuration:
 #      log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
 camera:
-  filepath: /home/xiaofei/uploads/taphole/
+  filepath: D:/opt/camera
   rtmp:
-    rtmphost: 172.28.1.10:1935
-    httphost: 150.158.22.179:18000
-    webrtchost: 192.168.110.130:8000
+    rtmphost: 127.0.0.1:1935
+    httphost: 127.0.0.1:80
+    webrtchost: 150.158.22.179:58000
 
 socketio:
-  #host: 0.0.0.0		#主机名,默认是 0.0.0.0 (这个设不设置无所谓,因为后面的 SocketConfig 类一般不用设置这个)
+  # host: 127.0.0.1		#主机名,默认是 0.0.0.0 (这个设不设置无所谓,因为后面的 SocketConfig 类一般不用设置这个)
   port: 33000			#监听端口
   maxFramePayloadLength: 1048576
   maxHttpContentLength: 1048576

+ 0 - 13
taphole-camera/src/main/java/com.sckj.camera/model/bo/CameraBO.java

@@ -1,13 +0,0 @@
-package com.sckj.camera.model.bo;
-
-import lombok.Data;
-
-import java.io.Serializable;
-
-@Data
-public class CameraBO implements Serializable {
-    private static final long serialVersionUID = 1L;
-    private Long id;
-    private String status;
-    private Integer sort;
-}

+ 0 - 24
taphole-camera/src/main/java/com.sckj.camera/service/CameraServiceImpl.java

@@ -1,12 +1,10 @@
 package com.sckj.camera.service;
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.sckj.camera.hik.HCNetTools;
 import com.sckj.camera.manager.CameraProperties;
 import com.sckj.camera.manager.HikCameraManager;
-import com.sckj.camera.model.bo.CameraBO;
 import com.sckj.camera.model.dto.CameraDTO;
 import com.sckj.camera.model.dto.ResultDTO;
 import com.sckj.camera.model.entity.Camera;
@@ -25,10 +23,8 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.RequestBody;
 
-import javax.annotation.PreDestroy;
 import javax.annotation.Resource;
 import java.io.File;
 import java.time.LocalDateTime;
@@ -434,25 +430,5 @@ public class CameraServiceImpl extends ServiceImpl<CameraMapper, Camera> {
 //        }
 //    }
 
-    @Transactional
-    public void updateBatchs(List<CameraBO> cameraList) {
-        for (CameraBO camera : cameraList) {
-            Camera queryData = getById(camera.getId());
-            if (ObjectUtils.isEmpty(queryData)) {
-                throw new OperateException(String.format("传入的ID不存在:%s", camera.getId()));
-            }
-
-            LambdaUpdateWrapper<Camera> wrapper = new LambdaUpdateWrapper<>();
-            wrapper.eq(Camera::getId, camera.getId());
-            if (ObjectUtils.isNotEmpty(camera.getStatus())) {
-                wrapper.set(Camera::getStatus, camera.getStatus());
-            }
-            if (camera.getSort() != null) {
-                wrapper.set(Camera::getSort, camera.getSort());
-            }
-            update(wrapper);
-        }
-    }
-
 
 }

+ 32 - 0
taphole-common/src/main/java/com/sckj/common/manager/TaskManager.java

@@ -0,0 +1,32 @@
+package com.sckj.common.manager;
+
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+@Component
+public class TaskManager {
+
+    private final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);
+    private final Map<String, ScheduledFuture<?>> tasks = new HashMap<>();
+
+    // 添加定时任务
+    public void addTask(String taskName, long initialDelay, long period, TimeUnit unit, Runnable task) {
+        ScheduledFuture<?> future = executorService.scheduleAtFixedRate(task, initialDelay, period, unit);
+        tasks.put(taskName, future);
+    }
+
+    // 取消定时任务
+    public void cancelTask(String taskName) {
+        ScheduledFuture<?> future = tasks.get(taskName);
+        if (future != null) {
+            future.cancel(true);
+            tasks.remove(taskName);
+        }
+    }
+}

+ 4 - 0
taphole-device/pom.xml

@@ -31,6 +31,10 @@
             <artifactId>velocity-engine-core</artifactId>
             <version>2.3</version>
         </dependency>
+        <dependency>
+            <groupId>com.sckj</groupId>
+            <artifactId>taphole-camera</artifactId>
+        </dependency>
     </dependencies>
 
 </project>

+ 8 - 8
taphole-device/src/main/java/com/sckj/device/controller/TCameraController.java

@@ -1,17 +1,17 @@
 package com.sckj.device.controller;
 
 import com.sckj.common.aop.Log;
-import com.sckj.device.service.ITCameraService;
+import com.sckj.common.core.AjaxResult;
+import com.sckj.common.core.PageResult;
 import com.sckj.common.validate.commons.IdValidate;
+import com.sckj.common.validate.commons.PageValidate;
+import com.sckj.common.validator.annotation.IDMust;
+import com.sckj.device.service.impl.TCameraServiceImpl;
 import com.sckj.device.validate.TCameraCreateValidate;
-import com.sckj.device.validate.TCameraUpdateValidate;
 import com.sckj.device.validate.TCameraSearchValidate;
-import com.sckj.common.validate.commons.PageValidate;
-import com.sckj.device.vo.TCameraListedVo;
+import com.sckj.device.validate.TCameraUpdateValidate;
 import com.sckj.device.vo.TCameraDetailVo;
-import com.sckj.common.core.AjaxResult;
-import com.sckj.common.core.PageResult;
-import com.sckj.common.validator.annotation.IDMust;
+import com.sckj.device.vo.TCameraListedVo;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.validation.annotation.Validated;
@@ -26,7 +26,7 @@ import java.util.List;
 public class TCameraController {
 
     @Resource
-    ITCameraService iTCameraService;
+    TCameraServiceImpl iTCameraService;
 
     @GetMapping("/list")
     @ApiOperation(value="摄像头列表")

+ 6 - 0
taphole-device/src/main/java/com/sckj/device/entity/TCamera.java

@@ -70,4 +70,10 @@ public class TCamera implements Serializable {
     @ApiModelProperty(value = "品牌(1-海康 0-其他)")
     private String brand;
 
+    @ApiModelProperty(value = "RTSP端口")
+    private String portRtsp;
+
+    @ApiModelProperty(value = "显示顺序")
+    private Integer sort;
+
 }

+ 0 - 71
taphole-device/src/main/java/com/sckj/device/service/ITCameraService.java

@@ -1,71 +0,0 @@
-package com.sckj.device.service;
-
-import com.sckj.common.core.AjaxResult;
-import com.sckj.common.validate.commons.PageValidate;
-import com.sckj.device.validate.TCameraCreateValidate;
-import com.sckj.device.validate.TCameraUpdateValidate;
-import com.sckj.device.validate.TCameraSearchValidate;
-import com.sckj.device.vo.TCameraListedVo;
-import com.sckj.device.vo.TCameraDetailVo;
-import com.sckj.common.core.PageResult;
-
-import java.util.List;
-
-/**
- * 摄像头服务接口类
- * @author zhanghao
- */
-public interface ITCameraService {
-
-    /**
-     * 摄像头列表
-     *
-     * @author zhanghao
-     * @param pageValidate 分页参数
-     * @param searchValidate 搜索参数
-     * @return PageResult<TCameraListedVo>
-     */
-    PageResult<TCameraListedVo> list(PageValidate pageValidate, TCameraSearchValidate searchValidate);
-
-    /**
-     * 摄像头详情
-     *
-     * @author zhanghao
-     * @param id 主键ID
-     * @return TCameraDetailVo
-     */
-    TCameraDetailVo detail(Integer id);
-
-    /**
-     * 摄像头新增
-     *
-     * @author zhanghao
-     * @param createValidate 参数
-     */
-    int add(TCameraCreateValidate createValidate);
-
-    /**
-     * 摄像头编辑
-     *
-     * @author zhanghao
-     * @param updateValidate 参数
-     */
-    int edit(TCameraUpdateValidate updateValidate);
-
-    /**
-     * 摄像头删除
-     *
-     * @author zhanghao
-     * @param id 主键ID
-     */
-    void del(Integer id);
-
-    /**
-     * 摄像头批量删除
-     *
-     * @author zhanghao
-     * @param ids 主键数组
-     */
-    AjaxResult<Object> del_ex(List<Long> ids);
-
-}

+ 111 - 38
taphole-device/src/main/java/com/sckj/device/service/impl/TCameraServiceImpl.java

@@ -1,27 +1,29 @@
 package com.sckj.device.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.github.yulichang.query.MPJQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.sckj.camera.manager.CameraProperties;
 import com.sckj.common.TapholeAdminThreadLocal;
 import com.sckj.common.core.AjaxResult;
+import com.sckj.common.exception.OperateException;
 import com.sckj.common.validate.commons.PageValidate;
-import com.sckj.device.service.ITCameraService;
 import com.sckj.device.validate.TCameraCreateValidate;
+import com.sckj.device.validate.TCameraUpdateDTO;
 import com.sckj.device.validate.TCameraUpdateValidate;
 import com.sckj.device.validate.TCameraSearchValidate;
+import com.sckj.device.vo.CameraDTO;
 import com.sckj.device.vo.TCameraListedVo;
 import com.sckj.device.vo.TCameraDetailVo;
-import com.sckj.common.config.GlobalConfig;
 import com.sckj.common.core.PageResult;
 import com.sckj.device.entity.TCamera;
 import com.sckj.device.mapper.TCameraMapper;
-import com.sckj.common.util.ListUtils;
-import com.sckj.common.util.TimeUtils;
-import com.sckj.common.util.UrlUtils;
+import org.apache.commons.lang3.ObjectUtils;
 import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.Assert;
 import org.springframework.util.CollectionUtils;
 
@@ -29,43 +31,45 @@ import javax.annotation.Resource;
 import java.util.*;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * 摄像头实现类
+ *
  * @author zhanghao
  */
 @Service
-public class TCameraServiceImpl implements ITCameraService {
-        
+public class TCameraServiceImpl extends ServiceImpl<TCameraMapper, TCamera> {
+
     @Resource
     TCameraMapper tCameraMapper;
 
     /**
      * 摄像头列表
      *
-     * @author zhanghao
-     * @param pageValidate 分页参数
+     * @param pageValidate   分页参数
      * @param searchValidate 搜索参数
      * @return PageResult<TCameraListedVo>
+     * @author zhanghao
      */
-    @Override
     public PageResult<TCameraListedVo> list(PageValidate pageValidate, TCameraSearchValidate searchValidate) {
-        Integer page  = pageValidate.getPageNo();
+        Integer page = pageValidate.getPageNo();
         Integer limit = pageValidate.getPageSize();
 
         QueryWrapper<TCamera> queryWrapper = new QueryWrapper<>();
         queryWrapper.orderByDesc("id");
 
         tCameraMapper.setSearch(queryWrapper, searchValidate, new String[]{
-            "=:no:str",
-            "like:name:str",
-            "=:model:str",
+                "=:no:str",
+                "like:name:str",
+                "=:model:str",
         });
 
         IPage<TCamera> iPage = tCameraMapper.selectPage(new Page<>(page, limit), queryWrapper.eq("type", "1"));
 
         List<TCameraListedVo> list = new LinkedList<>();
-        for(TCamera item : iPage.getRecords()) {
+        for (TCamera item : iPage.getRecords()) {
             TCameraListedVo vo = new TCameraListedVo();
             BeanUtils.copyProperties(item, vo);
             list.add(vo);
@@ -77,16 +81,15 @@ public class TCameraServiceImpl implements ITCameraService {
     /**
      * 摄像头详情
      *
-     * @author zhanghao
      * @param id 主键参数
      * @return TCamera
+     * @author zhanghao
      */
-    @Override
     public TCameraDetailVo detail(Integer id) {
         TCamera model = tCameraMapper.selectOne(
                 new QueryWrapper<TCamera>()
-                    .eq("id", id)
-                    .last("limit 1"));
+                        .eq("id", id)
+                        .last("limit 1"));
 
         Assert.notNull(model, "数据不存在");
 
@@ -98,13 +101,12 @@ public class TCameraServiceImpl implements ITCameraService {
     /**
      * 摄像头新增
      *
-     * @author zhanghao
      * @param createValidate 参数
+     * @author zhanghao
      */
-    @Override
     public int add(TCameraCreateValidate createValidate) {
         TCamera model = new TCamera();
-        if (!checkPortAndIp(createValidate.getPort(), createValidate.getIp())){
+        if (!checkPortAndIp(createValidate.getPort(), createValidate.getIp())) {
             return 0;
         }
         model.setCreateTime(new Date(System.currentTimeMillis()));
@@ -125,19 +127,18 @@ public class TCameraServiceImpl implements ITCameraService {
     /**
      * 摄像头编辑
      *
-     * @author zhanghao
      * @param updateValidate 参数
+     * @author zhanghao
      */
-    @Override
     public int edit(TCameraUpdateValidate updateValidate) {
         TCamera model = tCameraMapper.selectOne(
                 new QueryWrapper<TCamera>()
-                    .eq("id",  updateValidate.getId())
-                    .last("limit 1"));
+                        .eq("id", updateValidate.getId())
+                        .last("limit 1"));
 
         Assert.notNull(model, "数据不存在!");
 
-        if (!checkPortAndIp(updateValidate.getPort(), updateValidate.getIp())){
+        if (!checkPortAndIp(updateValidate.getPort(), updateValidate.getIp())) {
             return 0;
         }
 
@@ -154,14 +155,14 @@ public class TCameraServiceImpl implements ITCameraService {
         return tCameraMapper.updateById(model);
     }
 
-    public boolean checkPortAndIp(String port, String ip){
-        if (Integer.parseInt(port) > 65535 && Integer.parseInt(port) < 0){
+    public boolean checkPortAndIp(String port, String ip) {
+        if (Integer.parseInt(port) > 65535 && Integer.parseInt(port) < 0) {
             return false;
         }
         String IP_PATTERN = "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
         Pattern pattern = Pattern.compile(IP_PATTERN);
         Matcher matcher = pattern.matcher(ip);
-        if (!matcher.matches()){
+        if (!matcher.matches()) {
             return false;
         }
         return true;
@@ -170,15 +171,14 @@ public class TCameraServiceImpl implements ITCameraService {
     /**
      * 摄像头删除
      *
-     * @author zhanghao
      * @param id 主键ID
+     * @author zhanghao
      */
-    @Override
     public void del(Integer id) {
         TCamera model = tCameraMapper.selectOne(
                 new QueryWrapper<TCamera>()
-                    .eq("id", id)
-                    .last("limit 1"));
+                        .eq("id", id)
+                        .last("limit 1"));
 
         Assert.notNull(model, "数据不存在!");
 
@@ -188,20 +188,93 @@ public class TCameraServiceImpl implements ITCameraService {
     /**
      * 摄像头批量删除
      *
-     * @author zhanghao
      * @param ids 主键数组
+     * @author zhanghao
      */
-    @Override
     public AjaxResult<Object> del_ex(List<Long> ids) {
         List<TCamera> models = tCameraMapper.selectList(
                 new QueryWrapper<TCamera>()
                         .in("id", ids));
 
-        if (CollectionUtils.isEmpty(models)){
+        if (CollectionUtils.isEmpty(models)) {
             return AjaxResult.failed("数据不存在");
         }
         tCameraMapper.delete(new QueryWrapper<TCamera>().in("id", ids));
         return AjaxResult.success();
     }
 
+    @Resource
+    private CameraProperties cameraProperties;
+
+
+    public Map<String, Object> getCameraInfo() {
+        List<TCamera> cameraList = lambdaQuery().eq(TCamera::getType, "1").in(TCamera::getStatus, "1", "2").orderByAsc(TCamera::getSort).list();
+        Map<String, Object> map = new HashMap<>();
+        List<CameraDTO> collect = cameraList.stream().flatMap((item) -> {
+            CameraDTO dto = new CameraDTO();
+            BeanUtils.copyProperties(item, dto);
+            String channelNumberStr = 1 + "02"; //新通道(2012年之后设备,02代表子码流)
+            String rtspUrl = "rtsp://" + item.getAccount() + ":" + item.getPassword() + "@" + item.getIp() + ":" + item.getPortRtsp() + "/" + channelNumberStr + "?transportmode=unicast"; //新码流
+            dto.setRtspUrl(rtspUrl);
+            return Stream.of(dto);
+        }).collect(Collectors.toList());
+        map.put("cameraList", collect);
+
+        List<CameraDTO> bannerList = new ArrayList<>();
+        for (CameraDTO cameraDTO : collect) {
+            if ("2".equals(cameraDTO.getStatus())) {
+                bannerList.add(cameraDTO);
+            }
+        }
+        map.put("bannerList", bannerList);
+        map.put("rtmpUrl", "http://" + cameraProperties.getRtmp().getWebrtchost());
+        return map;
+    }
+
+    public Map<String, Object> getCameraParamInfo() {
+        List<TCamera> cameraList = lambdaQuery().eq(TCamera::getType, "1").in(TCamera::getStatus, "1", "2").orderByAsc(TCamera::getSort).list();
+        Map<String, Object> map = new HashMap<>();
+        List<CameraDTO> collect = cameraList.stream().flatMap((item) -> {
+            CameraDTO dto = new CameraDTO();
+            BeanUtils.copyProperties(item, dto);
+            return Stream.of(dto);
+        }).collect(Collectors.toList());
+
+        List<CameraDTO> normalList = new ArrayList<>();
+        List<CameraDTO> bannerList = new ArrayList<>();
+
+        for (CameraDTO cameraDTO : collect) {
+            if ("1".equals(cameraDTO.getStatus())) {
+                normalList.add(cameraDTO);
+            }
+            if ("2".equals(cameraDTO.getStatus())) {
+                bannerList.add(cameraDTO);
+            }
+        }
+        map.put("normalList", normalList);
+        map.put("bannerList", bannerList);
+        return map;
+    }
+
+
+    @Transactional
+    public void updateBatchs(List<TCameraUpdateDTO> cameraList) {
+        for (TCameraUpdateDTO camera : cameraList) {
+            TCamera queryData = getById(camera.getId());
+            if (ObjectUtils.isEmpty(queryData)) {
+                throw new OperateException(String.format("传入的ID不存在:%s", camera.getId()));
+            }
+
+            LambdaUpdateWrapper<TCamera> wrapper = new LambdaUpdateWrapper<>();
+            wrapper.eq(TCamera::getId, camera.getId());
+            if (ObjectUtils.isNotEmpty(camera.getStatus())) {
+                wrapper.set(TCamera::getStatus, camera.getStatus());
+            }
+            if (camera.getSort() != null) {
+                wrapper.set(TCamera::getSort, camera.getSort());
+            }
+            update(wrapper);
+        }
+    }
+
 }

+ 32 - 0
taphole-device/src/main/java/com/sckj/device/validate/TCameraUpdateDTO.java

@@ -0,0 +1,32 @@
+package com.sckj.device.validate;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+/**
+ * 摄像头参数
+ * @author zhanghao
+ */
+@Data
+@ApiModel("摄像头更新参数")
+public class TCameraUpdateDTO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull(message = "id参数必传")
+    @ApiModelProperty(value = "主键ID")
+    private Long id;
+
+    @NotNull(message = "status参数缺失")
+    @ApiModelProperty(value = "设备启用标志(1启用 0停用)")
+    private String status;
+
+    @NotNull(message = "显示顺序")
+    @ApiModelProperty(value = "显示顺序")
+    private Integer sort;
+
+}

+ 21 - 0
taphole-device/src/main/java/com/sckj/device/vo/CameraDTO.java

@@ -0,0 +1,21 @@
+package com.sckj.device.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+@ApiModel("摄像头信息")
+public class CameraDTO {
+    @ApiModelProperty(value = "id")
+    private Long id;
+
+    @ApiModelProperty(value = "设备启用标志(1启用 0停用)")
+    private String status;
+
+    @ApiModelProperty(value = "显示顺序")
+    private Integer sort;
+
+    @ApiModelProperty(value = "视频播放RTSP URL")
+    private String rtspUrl;
+}

+ 2 - 2
taphole-iron/pom.xml

@@ -32,11 +32,11 @@
         </dependency>
         <dependency>
             <groupId>com.sckj</groupId>
-            <artifactId>taphole-camera</artifactId>
+            <artifactId>taphole-warn</artifactId>
         </dependency>
         <dependency>
             <groupId>com.sckj</groupId>
-            <artifactId>taphole-warn</artifactId>
+            <artifactId>taphole-device</artifactId>
         </dependency>
     </dependencies>
 

+ 18 - 58
taphole-iron/src/main/java/com/sckj/iron/controller/TIronVisualScreenController.java

@@ -1,17 +1,15 @@
 package com.sckj.iron.controller;
 
 import com.github.pagehelper.PageHelper;
-import com.sckj.camera.manager.CameraProperties;
-import com.sckj.camera.model.bo.CameraBO;
-import com.sckj.camera.model.entity.Camera;
-import com.sckj.camera.service.CameraServiceImpl;
 import com.sckj.common.aop.Log;
 import com.sckj.common.aop.NotLogin;
 import com.sckj.common.aop.NotPower;
 import com.sckj.common.core.AjaxResult;
 import com.sckj.common.util.RedisUtils;
 import com.sckj.common.validate.commons.PageValidate;
-import com.sckj.iron.dto.CameraDTO;
+import com.sckj.device.entity.TCamera;
+import com.sckj.device.service.impl.TCameraServiceImpl;
+import com.sckj.device.validate.TCameraUpdateDTO;
 import com.sckj.iron.dto.IronParamDTO;
 import com.sckj.iron.entity.TIronParam;
 import com.sckj.iron.entity.TL2Data;
@@ -59,15 +57,11 @@ public class TIronVisualScreenController {
     TL2DataServiceImpl tl2DataService;
 
     @Resource
-    private CameraServiceImpl cameraService;
+    private TCameraServiceImpl cameraService;
 
     @Resource
     TIronParamServiceImpl iTIronParamService;
 
-    @Resource
-    private CameraProperties cameraProperties;
-
-
     @NotLogin
     @PostMapping("/login")
     @ApiOperation(value = "登录系统")
@@ -156,15 +150,22 @@ public class TIronVisualScreenController {
      *
      * @return
      */
+    @ApiOperation("获取摄像头播放信息")
+    @PostMapping("/getCameraInfo")
+    public AjaxResult getCameraInfo() {
+        return AjaxResult.success(cameraService.getCameraInfo());
+    }
+
+    /**
+     * 摄像头登录
+     *
+     * @return
+     */
     @ApiOperation("获取摄像头参数信息")
     @PostMapping("/getCameraParamInfo")
     public AjaxResult getCameraParamInfo() {
-        List<Camera> normalCameras = cameraService.lambdaQuery().eq(Camera::getType,"1").eq(Camera::getStatus, "1").orderByAsc(Camera::getSort).list();
-        List<Camera> bannerCameras = cameraService.lambdaQuery().eq(Camera::getType,"1").eq(Camera::getStatus, "2").orderByAsc(Camera::getSort).list();
         TIronParam tIronParam = iTIronParamService.lambdaQuery().eq(TIronParam::getParamType, "camera_param").eq(TIronParam::getParamName, "camera_play_duration").one();
-        Map<String, Object> map = new HashMap<>();
-        map.put("normalList", normalCameras);
-        map.put("bannerList", bannerCameras);
+        Map<String, Object> map = cameraService.getCameraParamInfo();
         map.put("cameraPlayDuration", tIronParam.getParamValue());
         return AjaxResult.success(map);
     }
@@ -176,7 +177,7 @@ public class TIronVisualScreenController {
      */
     @ApiOperation("更新摄像头轮播状态、顺序")
     @PostMapping("/updateCamera")
-    public AjaxResult updateCamera(@RequestBody List<CameraBO> cameraList) {
+    public AjaxResult updateCamera(@RequestBody List<TCameraUpdateDTO> cameraList) {
         if (ObjectUtils.isEmpty(cameraList)) {
             return AjaxResult.failed("传入数据为空!");
         }
@@ -184,49 +185,8 @@ public class TIronVisualScreenController {
         return AjaxResult.success();
     }
 
-
-    /**
-     * 摄像头播放
-     *
-     * @param cameraId 相机信息ID
-     * @return ResultDTO
-     */
-    @ApiOperation("播放摄像头")
-    @PostMapping("/playCamera")
-    public AjaxResult playCamera(Long cameraId) {
-        Camera camera = cameraService.getById(cameraId);
-        if (ObjectUtils.isEmpty(camera)) {
-            return AjaxResult.failed("该摄像头不存在!");
-        }
-        String channelNumberStr = 1 + "02"; //新通道(2012年之后设备,02代表子码流)
-        String rtspName = "rtsp://" + camera.getAccount() + ":" + camera.getPassword() + "@" + camera.getIp() + ":554/" + channelNumberStr + "?transportmode=unicast"; //新码流
-        String webrtcUrl = "http://" + cameraProperties.getRtmp().getWebrtchost();
-        CameraDTO cameraDTO = new CameraDTO();
-        cameraDTO.setRtmpUrl(webrtcUrl);
-        cameraDTO.setRtspUrl(rtspName);
-        return AjaxResult.success(cameraDTO);
-    }
-
-//    /**
-//     * 摄像头登录
-//     *
-//     * @return
-//     */
-//    @ApiOperation("更新摄像头轮播间隔")
-//    @PostMapping("/updateCameraParam")
-//    public AjaxResult updateCameraParam(Integer cameraPlayDuration) {
-//        try {
-//            iTIronParamService.lambdaUpdate().eq(TIronParam::getParamType, "camera_param").eq(TIronParam::getParamName, "camera_play_duration")
-//                    .set(TIronParam::getParamValue, cameraPlayDuration).update();
-//        } catch (Exception e) {
-//            e.printStackTrace();
-//            return AjaxResult.failed("失败");
-//        }
-//        return AjaxResult.success();
-//    }
-
     @PostMapping("/getIronParams")
-    @ApiOperation(value = "获取出铁参数设置(出铁诊断模型参数:iron_judge,摄像头轮播时长参数:camera_param,大屏趋势图轮播项:iron_trend)")
+    @ApiOperation(value = "获取出铁参数设置(paramType=>出铁诊断模型参数:iron_judge,摄像头轮播时长参数:camera_param,大屏趋势图轮播项:iron_trend)")
     public AjaxResult getIronParam(String paramType) {
         List<TIronParam> list = iTIronParamService.lambdaQuery().eq(TIronParam::getStatus, "1")
                 .eq(TIronParam::getParamType, paramType).orderByAsc(TIronParam::getSort).list();

+ 0 - 9
taphole-iron/src/main/java/com/sckj/iron/dto/CameraDTO.java

@@ -1,9 +0,0 @@
-package com.sckj.iron.dto;
-
-import lombok.Data;
-
-@Data
-public class CameraDTO {
-    private String rtspUrl;
-    private String rtmpUrl;
-}

+ 85 - 0
taphole-iron/src/main/java/com/sckj/iron/entity/TL2Material.java

@@ -0,0 +1,85 @@
+package com.sckj.iron.entity;
+
+import com.alibaba.excel.annotation.ExcelIgnore;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.annotation.write.style.ColumnWidth;
+import com.alibaba.excel.annotation.write.style.HeadFontStyle;
+import com.alibaba.excel.annotation.write.style.HeadRowHeight;
+import com.alibaba.excel.annotation.write.style.HeadStyle;
+import com.alibaba.excel.enums.poi.FillPatternTypeEnum;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.Serializable;
+import java.util.Date;
+
+@HeadStyle(fillPatternType = FillPatternTypeEnum.NO_FILL, fillForegroundColor = -1)
+@HeadFontStyle(fontHeightInPoints = 16)
+@HeadRowHeight(40)
+@Data
+@ApiModel("L2上料")
+@TableName("t_l2_material")
+public class TL2Material implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "创建时间")
+    @ExcelIgnore
+    private Date createTime;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    @ApiModelProperty(value = "id")
+    @ExcelIgnore
+    private Long id;
+
+    @ApiModelProperty(value = "锅炉编号")
+    @ExcelIgnore
+    private Long boilerId;
+
+    @ApiModelProperty(value = "铁口区域编号")
+    @ExcelProperty("铁口区域编号")
+    @ColumnWidth(25)
+    private Long tapholeId;
+
+    @ApiModelProperty(value = "L1发过来的charge号")
+    @ExcelProperty("L1发过来的charge号")
+    @ColumnWidth(25)
+    private String chargeNo;
+
+    @ApiModelProperty(value = "下料时间点")
+    @ExcelProperty("下料时间点")
+    @ColumnWidth(25)
+    private String downTime;
+
+    @ApiModelProperty(value = "干量")
+    @ExcelProperty("干量")
+    @ColumnWidth(25)
+    private String dryWeight;
+
+
+    public void toDataStream(DataOutputStream dos) throws Exception {
+        dos.writeLong(tapholeId);
+        dos.writeLong(boilerId);
+        dos.writeUTF(chargeNo);
+        dos.writeUTF(downTime);
+        dos.writeUTF(dryWeight);
+    }
+
+    public static TL2Material fromDataStream(DataInputStream dis) throws Exception {
+        TL2Material data = new TL2Material();
+        data.tapholeId = dis.readLong();
+        data.boilerId = dis.readLong();
+        data.chargeNo = dis.readUTF();
+        data.downTime = dis.readUTF();
+        data.dryWeight = dis.readUTF();
+        return data;
+    }
+
+
+}

+ 13 - 0
taphole-iron/src/main/java/com/sckj/iron/mapper/TL2MaterialMapper.java

@@ -0,0 +1,13 @@
+package com.sckj.iron.mapper;
+
+import com.sckj.common.core.basics.IBaseMapper;
+import com.sckj.iron.entity.TL2Material;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 出铁后Mapper
+ * @author zhanghao
+ */
+@Mapper
+public interface TL2MaterialMapper extends IBaseMapper<TL2Material> {
+}

+ 38 - 0
taphole-iron/src/main/java/com/sckj/iron/service/impl/TL2MaterialServiceImpl.java

@@ -0,0 +1,38 @@
+package com.sckj.iron.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.sckj.common.util.ExcelUtils;
+import com.sckj.iron.entity.TL2Data;
+import com.sckj.iron.entity.TL2Material;
+import com.sckj.iron.mapper.TL2MaterialMapper;
+import org.apache.commons.lang3.ObjectUtils;
+import org.springframework.stereotype.Service;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * L2数据
+ *
+ * @author zhnaghao
+ */
+@Service
+public class TL2MaterialServiceImpl extends ServiceImpl<TL2MaterialMapper, TL2Material> {
+
+
+    /***
+     * 获取最新2条数据
+     * @return
+     */
+    public List<TL2Material> getLatest2Data() {
+        LambdaQueryWrapper<TL2Material> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.isNotNull(TL2Material::getChargeNo).orderByDesc(TL2Material::getChargeNo).last("limit 2");
+        List<TL2Material> list = list(queryWrapper);
+        return list;
+    }
+
+
+}

+ 77 - 49
taphole-iron/src/main/java/com/sckj/iron/socketio/DeviceEventListener.java

@@ -8,6 +8,7 @@ import com.google.common.eventbus.Subscribe;
 import com.sckj.camera.util.LocalDateUtils;
 import com.sckj.common.core.AjaxResult;
 import com.sckj.common.eventbus.EventListener;
+import com.sckj.common.manager.TaskManager;
 import com.sckj.common.socketio.SocketUtil;
 import com.sckj.common.util.RedisUtils;
 import com.sckj.iron.dto.IronStepDTO;
@@ -15,9 +16,11 @@ import com.sckj.iron.dto.RealtimeData;
 import com.sckj.iron.entity.TIronData;
 import com.sckj.iron.entity.TIronParam;
 import com.sckj.iron.entity.TL2Data;
+import com.sckj.iron.entity.TL2Material;
 import com.sckj.iron.service.impl.*;
 import com.sckj.iron.vo.IronStepVO;
 import com.sckj.opc.dto.L2Data;
+import com.sckj.opc.dto.L2Material;
 import com.sckj.opc.entity.OPCData;
 import com.sckj.opc.opcua.L2DataServiceImpl;
 import com.sckj.opc.opcua.OPCDAServiceImpl;
@@ -37,8 +40,8 @@ import java.math.BigDecimal;
 import java.time.LocalDateTime;
 import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
-import java.util.stream.Stream;
 
 /**
  * @Author feng
@@ -73,6 +76,10 @@ public class DeviceEventListener extends EventListener {
     @Resource
     TL2DataServiceImpl tl2DataService;
 
+    //参数
+    @Resource
+    TL2MaterialServiceImpl tl2MaterialService;
+
     @Resource
     L2DataServiceImpl l2DataServiceImpl;
 
@@ -85,7 +92,6 @@ public class DeviceEventListener extends EventListener {
     @Resource
     OPCDAServiceImpl opcdaService;
 
-
     //1号出铁状态标记
     private static final String TAG_TAPHOLE1_STATUS = "AOD25606.PV";
     //2号出铁状态标记
@@ -153,8 +159,19 @@ public class DeviceEventListener extends EventListener {
 
     private static final String NODE = "node";
 
-    //定时器,用于铁口开口超时记录
-    private Timer timer = new Timer();
+    //定时器
+    @Resource
+    private TaskManager taskManager;
+
+    //开口预警
+    private static final String TASKNAME_OPEN = "openHour";
+    //堵口预警
+    private static final String TASKNAME_MUD = "mud";
+    //出铁预警
+    private static final String TASKNAME_IRON_START = "ironStart";
+    //出铁诊断
+    private static final String TASKNAME_IRON_END = "ironEnd";
+
 
     //是否出铁中
     //1 出铁中    0 出铁结束
@@ -171,20 +188,27 @@ public class DeviceEventListener extends EventListener {
 
     private float speed1, speed2;
 
+    //标准流速
+    private float STANDARD_SPEED;
+    //开口耗时
+    private int OPEND_HOUR;
+
     @PostConstruct
     public void init() {
-        timer.schedule(new TimerTask() {
-            @Override
-            public void run() {
-                opcdaService.subscribeAvailable();
-            }
-        }, 10 * 1000);
+        taskManager.addTask("openHour", 0, 10, TimeUnit.SECONDS, () -> {
+            log.info("opcdaService subscribe available");
+//           opcdaService.subscribeAvailable();
+        });
+
         mSteps = ironStepService.getTreeSteps();
         List<TIronParam> mIronParams = ironParamService.lambdaQuery().eq(TIronParam::getStatus, "1").eq(TIronParam::getParamType, "iron_judge").orderByAsc(TIronParam::getSort).list();
         if (ObjectUtils.isNotEmpty(mIronParams)) {
             mIronParamMap = mIronParams.stream()
                     .collect(Collectors.toMap(TIronParam::getParamName, ironParam -> ironParam, (existing, replacement) -> existing));
+            STANDARD_SPEED = Float.parseFloat(mIronParamMap.get("iron_speed").getParamValue());
+            OPEND_HOUR = Integer.parseInt(mIronParamMap.get("open_hours").getParamValue());
         }
+
     }
 
     /***
@@ -212,7 +236,7 @@ public class DeviceEventListener extends EventListener {
      * @param l2Data
      */
     @Subscribe
-    public void onL2MessageEvent(L2Data l2Data) {
+    public void onL2DataMessageEvent(L2Data l2Data) {
         TL2Data tl2Data = new TL2Data();
         //出铁操作
         BeanUtils.copyProperties(l2Data, tl2Data);
@@ -280,7 +304,6 @@ public class DeviceEventListener extends EventListener {
                                         childChild.setData(ironWeightLastLast);
                                     }
                                 }
-
                             }
                         }
                     }
@@ -292,6 +315,18 @@ public class DeviceEventListener extends EventListener {
 
     }
 
+
+    @Subscribe
+    public void onL2MaterialMessageEvent(L2Material l2Material) {
+        TL2Material tl2Material = new TL2Material();
+        //出铁操作
+        BeanUtils.copyProperties(l2Material, tl2Material);
+        //将L2上料实时数据保存到数据库
+        taskExecutor.submit(() -> {
+            tl2MaterialService.saveOrUpdate(tl2Material);
+        });
+    }
+
     //1号铁口正在出铁的操作项目
     private void taphole1Start(L2Data mL2Data) {
         //通过“预判和确认出铁”标记开始出铁
@@ -306,21 +341,15 @@ public class DeviceEventListener extends EventListener {
 
         //炉前在接受到炉内出铁要求后,10分钟内打开铁口,未打开系统告警并记录
         if (isReady) {
-            TimerTask task = new TimerTask() {
-                @Override
-                public void run() {
-                    System.out.println("倒计时结束!10分钟已到。");
-                    timer.cancel(); // 终止定时器
-                    // 出铁预警,打开系统告警并记录
-                    PushData.send2Warn("请立即打开铁口");
-                    log.info("准备出铁但是未及时出铁口,此处数据库记录");
-                }
-            };
+            taskManager.addTask(TASKNAME_OPEN, 0, OPEND_HOUR, TimeUnit.MINUTES, () -> {
+                log.info("堵口预警:{}", TASKNAME_OPEN);
+                taskManager.cancelTask(TASKNAME_OPEN); // 终止定时器
+                System.out.println("倒计时结束!10分钟已到。");
+                // 出铁预警,打开系统告警并记录
+                PushData.send2Warn("请立即打开铁口");
+                log.info("准备出铁但是未及时出铁口,此处数据库记录");
+            });
 
-            // 倒计时10分钟(600秒)
-            long delay = 10 * 60 * 1000; // 10分钟转换为毫秒
-            // 在指定延迟后执行任务
-            timer.schedule(task, delay);
         }
 
 
@@ -348,24 +377,20 @@ public class DeviceEventListener extends EventListener {
 
         //开始计算打泥量,通过打泥量公式
         //打泥量公式关联因素:铁口深度、钻杆直径、
-        //
-
-        timer.schedule(new TimerTask() {
-            @Override
-            public void run() {
-                //堵口预警
-                if (speed1 > 20 || speed2 > 20) {
-                    /// 流速过大可能是由于铁口深度不足或发生跑大流问题,则提示将当前铁口堵口
-                    PushData.send2Warn("流速过快,堵口");
-                } else if ((speed1 < 20 || speed2 < 20) && (ironLoading2 || ironLoading3 || ironLoading4)) {
-                    //若流速过小,但其它铁口正在出铁,则提示将当前铁口堵口
-                    PushData.send2Warn("当前铁口堵口");
-                } else if ((speed1 < 20 || speed2 < 20) && (!ironLoading2 && !ironLoading3 && !ironLoading4)) {
-                    //若流速过小且其他铁口均未出铁,则提示先将其它铁口打开,再进行堵口
-                    PushData.send2Warn("先将其它铁口打开,再进行堵口");
-                }
+        taskManager.addTask(TASKNAME_MUD, 0, 1, TimeUnit.MINUTES, () -> {
+            //堵口预警
+            log.info("堵口预警:{},speed1:{},speed2:{},STANDARD_SPEED:{}", speed1, speed2, TASKNAME_OPEN);
+            if (speed1 > STANDARD_SPEED || speed2 > STANDARD_SPEED) {
+                /// 流速过大可能是由于铁口深度不足或发生跑大流问题,则提示将当前铁口堵口
+                PushData.send2Warn("流速过快,请堵口");
+            } else if ((speed1 < STANDARD_SPEED || speed2 < STANDARD_SPEED) && (ironLoading2 || ironLoading3 || ironLoading4)) {
+                //若流速过小,但其它铁口正在出铁,则提示将当前铁口堵口
+                PushData.send2Warn("请堵口");
+            } else if ((speed1 < STANDARD_SPEED || speed2 < STANDARD_SPEED) && (!ironLoading2 && !ironLoading3 && !ironLoading4)) {
+                //若流速过小且其他铁口均未出铁,则提示先将其它铁口打开,再进行堵口
+                PushData.send2Warn("请先将其它铁口打开,再堵口");
             }
-        }, 10 * 60 * 1000);
+        });
 
 
     }
@@ -374,11 +399,9 @@ public class DeviceEventListener extends EventListener {
     private void taphole1End() {
         //由 1-> 0 表明1号铁口结束出铁
         totalWeight = BigDecimal.ZERO;
-        try {
-            timer.cancel(); // 终止定时器
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
+        taskManager.cancelTask(TASKNAME_OPEN);
+        taskManager.cancelTask(TASKNAME_MUD);
+        taskManager.cancelTask(TASKNAME_IRON_START);
         recordAfter();
         recordBlock();
 
@@ -389,7 +412,12 @@ public class DeviceEventListener extends EventListener {
         //开始出铁诊断
         //获取开口耗时、出铁时间、实际出铁量、平均铁水流速、平均铁水温度等数据,进行阈值判定,诊断出铁是否正常
 
-        //1分钟延迟
+        //10分钟延迟
+        taskManager.addTask(TASKNAME_IRON_END, 0, 10, TimeUnit.MINUTES, () -> {
+            //堵口预警
+            log.info("定时任务:{},出铁诊断", TASKNAME_IRON_END);
+            taskManager.cancelTask(TASKNAME_IRON_END);
+        });
 
     }
 

+ 57 - 0
taphole-opc/src/main/java/com/sckj/opc/dto/L2Material.java

@@ -0,0 +1,57 @@
+package com.sckj.opc.dto;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class L2Material implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "创建时间")
+    private Date createTime;
+
+    @TableId(value="id", type= IdType.AUTO)
+    @ApiModelProperty(value = "id")
+    private Long id;
+
+    @ApiModelProperty(value = "锅炉编号")
+    private Long boilerId;
+
+    @ApiModelProperty(value = "铁口区域编号")
+    private Long tapholeId;
+
+    @ApiModelProperty(value = "L1发过来的charge号")
+    private String chargeNo;
+
+    @ApiModelProperty(value = "下料时间点")
+    private String downTime;
+
+    @ApiModelProperty(value = "干量")
+    private String dryWeight;
+
+
+    public void toDataStream(DataOutputStream dos) throws Exception {
+        dos.writeUTF(chargeNo);
+        dos.writeUTF(downTime);
+        dos.writeUTF(dryWeight);
+    }
+
+    public static L2Material fromDataStream(DataInputStream dis) throws Exception {
+        L2Material data = new L2Material();
+        data.chargeNo = dis.readUTF();
+        data.downTime = dis.readUTF();
+        data.dryWeight = dis.readUTF();
+        return data;
+    }
+
+
+
+}

+ 13 - 4
taphole-opc/src/main/java/com/sckj/opc/opcua/L2DataServiceImpl.java

@@ -2,6 +2,7 @@ package com.sckj.opc.opcua;
 
 import com.google.common.eventbus.AsyncEventBus;
 import com.sckj.opc.dto.L2Data;
+import com.sckj.opc.dto.L2Material;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@@ -84,10 +85,18 @@ public class L2DataServiceImpl {
             while (true) {
                 try {
                     // 从输入流读取L2Data对象
-                    L2Data receivedData = L2Data.fromDataStream(dis);
-                    //出铁操作
-                    asyncEventBus.post(receivedData);
-                    System.out.println("Received L2Data from server: \n" + receivedData);
+                    // 新增:读取数据类型标识(需要服务端配合发送类型头)
+                    String dataType = dis.readUTF();
+                    if ("L2Data".equals(dataType)) {
+                        L2Data receivedData = L2Data.fromDataStream(dis);
+                        asyncEventBus.post(receivedData); //出铁操作
+                        System.out.println("Received L2Data from server: \n" + receivedData);
+                    } else if ("L2Material".equals(dataType)) {
+                        L2Material receivedMaterial = L2Material.fromDataStream(dis);
+                        // 新增材料处理逻辑,例如:
+                         asyncEventBus.post(receivedMaterial);
+                        System.out.println("Received L2Material from server: \n" + receivedMaterial);
+                    }
                 } catch (IOException e) {
                     System.err.println("Connection lost. Attempting to reconnect...");
                     socket.close();