hecheng лет назад: 3
Родитель
Сommit
b93d9c2b28

+ 1 - 0
docker/mysql/update/bottle-update.sql

@@ -0,0 +1 @@
+ALTER TABLE ab_alarm_record ADD attachment_url varchar(250) COMMENT '报警照片附件';

+ 9 - 3
zd-api/zd-api-system/src/main/java/com/zd/system/api/forward/RemoteForwardService.java

@@ -2,17 +2,20 @@ package com.zd.system.api.forward;
 
 import com.zd.common.core.constant.ServiceNameConstants;
 import com.zd.common.core.domain.R;
+import com.zd.system.api.domain.SysFile;
 import com.zd.system.api.forward.factory.RemoteForwardFallbackFactory;
 import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestParam;
 
 import java.util.Map;
 
 /**
  * 消息内容feign调用服务
  */
-@FeignClient(contextId = "remoteForwardService", value = ServiceNameConstants.LABORATORY_SERVICE, fallbackFactory = RemoteForwardFallbackFactory.class)
+@FeignClient(contextId = "remoteForwardService", value = ServiceNameConstants.FORWARD_SERVICE, fallbackFactory = RemoteForwardFallbackFactory.class)
 public interface RemoteForwardService {
 
 
@@ -20,9 +23,12 @@ public interface RemoteForwardService {
      * 保存检查记录
      */
     @PostMapping("/checklog")
-    public R add(@RequestBody Map<String,Object> map);
+    R add(@RequestBody Map<String,Object> map);
 
 
     @PostMapping("/algorithm/save")
-    public Object saveData(@RequestBody Map<String, Object> data);
+    Object saveData(@RequestBody Map<String, Object> data);
+
+    @GetMapping("/alarm/photograph")
+    R<SysFile> photograph(@RequestParam("streamUrl") String streamUrl);
 }

+ 6 - 2
zd-api/zd-api-system/src/main/java/com/zd/system/api/forward/factory/RemoteForwardFallbackFactory.java

@@ -1,6 +1,7 @@
 package com.zd.system.api.forward.factory;
 
 import com.zd.common.core.domain.R;
+import com.zd.system.api.domain.SysFile;
 import com.zd.system.api.forward.RemoteForwardService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -24,8 +25,6 @@ public class RemoteForwardFallbackFactory implements FallbackFactory<RemoteForwa
         return new RemoteForwardService() {
             /**
              * 保存检查记录
-             *
-             * @param map
              */
             @Override
             public R add(Map<String, Object> map) {
@@ -37,6 +36,11 @@ public class RemoteForwardFallbackFactory implements FallbackFactory<RemoteForwa
 
                 return R.fail("保存调用失败:" + throwable.getMessage());
             }
+
+            @Override
+            public R<SysFile> photograph(String streamUrl) {
+                return R.fail("报警拍照服务调用失败:" + throwable.getMessage());
+            }
         };
     }
 }

+ 6 - 0
zd-common/zd-common-core/src/main/java/com/zd/common/core/constant/ServiceNameConstants.java

@@ -33,6 +33,12 @@ public class ServiceNameConstants {
 
 
     /**
+     * 算法转发服务
+     */
+    public static final String FORWARD_SERVICE = "zd-forward";
+
+
+    /**
      * 人脸识别的serviceid
      */
     public static final String FACE_SERVICE = "zd-face";

+ 3 - 0
zd-modules/zd-bottle-parent/zd-bottle-api/src/main/java/com/zd/bottle/domain/AlarmRecord.java

@@ -34,6 +34,9 @@ public class AlarmRecord extends BaseBean{
     @ApiModelProperty("电子标签")
     private String electronicTag;
 
+    @ApiModelProperty("报警照片附件")
+    private String attachmentUrl;
+
     @ApiModelProperty("报警类型;1:出门,2:进门")
     private Integer type;
 

+ 27 - 0
zd-modules/zd-bottle-parent/zd-bottle/src/main/java/com/zd/bottle/properties/AlarmProperties.java

@@ -0,0 +1,27 @@
+package com.zd.bottle.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author Administrator
+ */
+@Configuration
+@ConfigurationProperties("alarm")
+@RefreshScope
+@Data
+public class AlarmProperties {
+
+    /**
+     * 视频流地址
+     */
+    private String streamUrl;
+
+    /**
+     * 间隔时间
+     */
+    private Integer waitTime=1;
+
+}

+ 36 - 10
zd-modules/zd-bottle-parent/zd-bottle/src/main/java/com/zd/bottle/service/impl/AlarmRecordServiceImpl.java

@@ -8,6 +8,7 @@ import com.zd.bottle.domain.BottleStorage;
 import com.zd.bottle.domain.RfidTag;
 import com.zd.bottle.domain.UsegasApply;
 import com.zd.bottle.mapper.AlarmRecordMapper;
+import com.zd.bottle.properties.AlarmProperties;
 import com.zd.bottle.service.AlarmRecordService;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.zd.bottle.service.BottleStorageService;
@@ -25,6 +26,8 @@ import com.zd.system.api.alarm.domain.AlarmEntrty;
 import com.zd.system.api.alarm.domain.Routes;
 import com.zd.system.api.alarm.domain.SendTypes;
 import com.zd.system.api.domain.InventoryTag;
+import com.zd.system.api.domain.SysFile;
+import com.zd.system.api.forward.RemoteForwardService;
 import com.zd.system.api.laboratory.RemoteLaboratoryService;
 import com.zd.system.api.laboratory.RemoteSubQueryService;
 import com.zd.system.api.laboratory.domain.LabSubject;
@@ -34,6 +37,7 @@ import com.zd.system.api.netty.RemoteNettyService;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.concurrent.BasicThreadFactory;
 import org.apache.poi.util.StringUtil;
+import org.jetbrains.annotations.Nullable;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.StringUtils;
@@ -80,6 +84,12 @@ public class AlarmRecordServiceImpl extends ServiceImpl<AlarmRecordMapper, Alarm
     @Resource
     private UsegasApplyService applyService;
 
+    @Resource
+    private RemoteForwardService remoteForwardService;
+
+    @Resource
+    private AlarmProperties alarmProperties;
+
     private static final String MSG_MATCH = "==================>{},{}";
 
     @Override
@@ -127,18 +137,12 @@ public class AlarmRecordServiceImpl extends ServiceImpl<AlarmRecordMapper, Alarm
         if (bottleStorage != null) {
             String airName = bottleStorage.getAirName();
             LambdaQueryWrapper<UsegasApply> lambdaQuery = Wrappers.lambdaQuery(UsegasApply.class);
-            lambdaQuery.eq(UsegasApply::getUseGasName,airName)
-                    .ge(UsegasApply::getEndTime, DateUtil.formatDate(Calendar.getInstance().getTime())).eq(UsegasApply::getLeadAuditStaus,1);
+            lambdaQuery.eq(UsegasApply::getUseGasName, airName)
+                    .ge(UsegasApply::getEndTime, DateUtil.formatDate(Calendar.getInstance().getTime())).eq(UsegasApply::getLeadAuditStaus, 1);
             List<UsegasApply> applies = applyService.list(lambdaQuery);
-            if (applies.isEmpty()){
+            if (applies.isEmpty()) {
                 Long id = bottleStorage.getId();
-                //触发RFID警报
-                if (hardware!=null){
-                    R<Boolean> alarm = remoteNettyService.alarm(hardware);//RFID设备报警
-                    log.info(MSG_MATCH,alarm.getCode(),alarm.getMsg());
-                }else {
-                    log.info("==================> rfid 参数有误!"+ tag);
-                }
+                R<SysFile> fileR = getFileR(tag, hardware);
                 String key = FRID_CODE + electronicTag + id;
                 String frid = redisService.getCacheObject(key);
                 if (frid != null) {
@@ -148,6 +152,10 @@ public class AlarmRecordServiceImpl extends ServiceImpl<AlarmRecordMapper, Alarm
                 sendAlarm(bottleStorage);
                 redisService.setCacheObject(key, electronicTag, 300L, TimeUnit.SECONDS);
                 AlarmRecord alarmRecord = new AlarmRecord();
+                if (fileR != null && fileR.getCode() == HttpStatus.SUCCESS && fileR.getData() != null) {
+                    SysFile data = fileR.getData();
+                    alarmRecord.setAttachmentUrl(data.getUrl());
+                }
                 alarmRecord.setElectronicTag(electronicTag)
                         .setAlarmTime(Calendar.getInstance().getTime())
                         .setMasterId(id)
@@ -164,6 +172,24 @@ public class AlarmRecordServiceImpl extends ServiceImpl<AlarmRecordMapper, Alarm
         return false;
     }
 
+    @Nullable
+    private R<SysFile> getFileR(InventoryTag tag, RemoteLabHardware hardware) {
+        //触发RFID警报
+        if (hardware != null) {
+            R<Boolean> alarm = remoteNettyService.alarm(hardware);//RFID设备报警
+            log.info(MSG_MATCH, alarm.getCode(), alarm.getMsg());
+        } else {
+            log.info("==================> rfid 参数有误!" + tag);
+        }
+        String streamUrl = alarmProperties.getStreamUrl();
+        if (StringUtils.hasLength(streamUrl)) {
+            R<SysFile> fileR = remoteForwardService.photograph(alarmProperties.getStreamUrl());
+            log.info("文件上传状态:{},接口返回消息:{},文件上传路径:{}", fileR.getCode(), fileR.getMsg(), fileR.getData());
+            return fileR;
+        }
+        return null;
+    }
+
     private void sendAlarm(BottleStorage storage) {
         Long subjectId = storage.getSubjectId();
         R<List<LabSubject>> resultList = remoteSubQueryService.listByIds(Collections.singletonList(subjectId));

+ 27 - 0
zd-modules/zd-chemical/src/main/java/com/zd/chemical/properties/AlarmProperties.java

@@ -0,0 +1,27 @@
+package com.zd.chemical.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author Administrator
+ */
+@Configuration
+@ConfigurationProperties("alarm")
+@RefreshScope
+@Data
+public class AlarmProperties {
+
+    /**
+     * 视频流地址
+     */
+    private String streamUrl;
+
+    /**
+     * 间隔时间
+     */
+    private Integer waitTime=1;
+
+}

+ 17 - 0
zd-modules/zd-chemical/src/main/java/com/zd/chemical/service/impl/HxpStockServiceImpl.java

@@ -6,6 +6,7 @@ import com.zd.chemical.controller.HxpAIOController;
 import com.zd.chemical.domain.*;
 import com.zd.chemical.domain.vo.*;
 import com.zd.chemical.mapper.*;
+import com.zd.chemical.properties.AlarmProperties;
 import com.zd.chemical.service.*;
 import com.zd.chemical.util.SmsSydUtil;
 import com.zd.common.core.domain.R;
@@ -22,6 +23,8 @@ import com.zd.system.api.alarm.domain.AlarmEntrty;
 import com.zd.system.api.alarm.domain.Routes;
 import com.zd.system.api.domain.InventoryTag;
 import com.zd.system.api.domain.SysDictData;
+import com.zd.system.api.domain.SysFile;
+import com.zd.system.api.forward.RemoteForwardService;
 import com.zd.system.api.laboratory.RemoteLaboratoryService;
 import com.zd.system.api.laboratory.RemoteMessageContentService;
 import com.zd.system.api.laboratory.domain.RemoteLabHardware;
@@ -101,6 +104,11 @@ public class HxpStockServiceImpl implements IHxpStockService {
     private RemoteNettyService remoteNettyService;
     @Resource
     private SmsSydUtil smsSydUtil;
+
+    @Resource
+    private AlarmProperties alarmProperties;
+    @Resource
+    private RemoteForwardService remoteForwardService;
     /**
      * 查询库存管理
      *
@@ -333,6 +341,14 @@ public class HxpStockServiceImpl implements IHxpStockService {
             return false;
         }else {
             logger.error("RFID 检测到违规触发报警: " + JSONUtil.toJsonStr(hxpStock));
+            String streamUrl = alarmProperties.getStreamUrl();
+            R<SysFile> fileR = null;
+            if (org.springframework.util.StringUtils.hasLength(streamUrl)){
+                fileR= remoteForwardService.photograph(alarmProperties.getStreamUrl());
+            }
+            if (fileR!=null){
+                logger.info("文件上传状态:{},接口返回消息:{},文件上传路径:{}",fileR.getCode(),fileR.getMsg(),fileR.getData());
+            }
             //触发RFID警报
             RemoteLabHardware hardware = tag.getRemoteLabHardware();
             boolean isAlarm = false;
@@ -389,6 +405,7 @@ public class HxpStockServiceImpl implements IHxpStockService {
                 hxpAlarmRecord.setSubId(hxpStock.getSubId());
                 hxpAlarmRecord.setTerminalNum(terminalNum == null ? tag.getSerialNumber() : terminalNum);
                 hxpAlarmRecord.setHandlingStatus(1);
+                // TODO 请在此处新增图片路径字段并使用 fileR 中的返回值url作为图片路径以供前端调用,具体实现方式可参考 com.zd.bottle.service.impl.AlarmRecordServiceImpl.remoteAdd#155 行代码,默认配置为空,具体配置可参考zd-bottle-dev.yml#113行到115行
 
                 hxpAlarmRecordMapper.insertHxpAlarmRecord(hxpAlarmRecord);
             }

+ 5 - 0
zd-modules/zd-forward/pom.xml

@@ -96,6 +96,11 @@
             <version>1.5.7</version>
         </dependency>
 
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-mock</artifactId>
+            <version>2.0.8</version>
+        </dependency>
     </dependencies>
     <build>
         <finalName>${project.artifactId}</finalName>

+ 45 - 0
zd-modules/zd-forward/src/main/java/com/zd/forward/controller/AlarmController.java

@@ -0,0 +1,45 @@
+package com.zd.forward.controller;
+
+
+import com.github.xiaoymin.knife4j.annotations.ApiSupport;
+import com.zd.common.core.domain.R;
+import com.zd.common.core.exception.ServiceException;
+import com.zd.common.swagger.config.Knife4jConfiguration;
+import com.zd.forward.serivce.ImageService;
+import com.zd.system.api.domain.SysFile;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.io.IOException;
+
+/**
+ * 报警拍照服务
+ */
+@Api(tags = {"报警拍照服务"})
+@ApiSupport(author = Knife4jConfiguration.Author.ZP)
+@RestController
+@RequestMapping("/alarm")
+public class AlarmController {
+
+    @Resource
+    private ImageService imageService;
+
+    @ApiOperation(value = "拍照")
+    @GetMapping("/photograph")
+    public R<SysFile> photograph(@RequestParam("streamUrl") String streamUrl) {
+        try {
+            SysFile sysFile = imageService.photograph(streamUrl);
+            if (sysFile!=null){
+                return R.ok(sysFile);
+            }
+            return R.fail("图片抓拍失败");
+        } catch (IOException|ServiceException e) {
+            throw new ServiceException(e.getMessage());
+        }
+    }
+}

+ 1 - 10
zd-modules/zd-forward/src/main/java/com/zd/forward/serivce/FireImageService.java

@@ -31,6 +31,7 @@ import java.util.Optional;
 
 import static com.zd.forward.utils.HttpUtils.getHttpEntityMap;
 import static com.zd.forward.utils.HttpUtils.multipartFileToFile;
+import static com.zd.forward.utils.VideoUtils.frameToBufferedImage;
 
 /**
  * 火焰图片抓拍处理
@@ -128,14 +129,4 @@ public class FireImageService {
             }
         }
     }
-
-    /**
-     * frame 转图片流
-     */
-    public static BufferedImage frameToBufferedImage(Frame frame) {
-        //创建BufferedImage对象
-        try (Java2DFrameConverter converter = new Java2DFrameConverter()) {
-            return converter.getBufferedImage(frame);
-        }
-    }
 }

+ 81 - 0
zd-modules/zd-forward/src/main/java/com/zd/forward/serivce/ImageService.java

@@ -0,0 +1,81 @@
+package com.zd.forward.serivce;
+
+
+import com.zd.common.core.constant.HttpStatus;
+import com.zd.common.core.domain.R;
+import com.zd.common.core.exception.ServiceException;
+import com.zd.forward.utils.VideoUtils;
+import com.zd.system.api.RemoteFileService;
+import com.zd.system.api.domain.SysFile;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.entity.ContentType;
+import org.bytedeco.javacv.FFmpegFrameGrabber;
+import org.bytedeco.javacv.Frame;
+import org.springframework.mock.web.MockMultipartFile;
+import org.springframework.stereotype.Service;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.rmi.ServerException;
+
+import static com.zd.forward.utils.VideoUtils.frameToBufferedImage;
+
+/**
+ * @author hanson
+ */
+@Service
+@Slf4j
+public class ImageService {
+
+    @Resource
+    private RemoteFileService remoteFileService;
+
+    /**
+     * 生成的图片的类型
+     */
+    private static final String IMAGE_FORMAT = "jpg";
+
+    public SysFile photograph(String streamUrl) throws IOException {
+        try (FFmpegFrameGrabber grabber = VideoUtils.createGrabber(streamUrl)) {
+            grabber.start();
+            String fileName = "test";
+            //文件储存对象
+            File file = new File(fileName + "." + IMAGE_FORMAT);
+            //获取第一帧
+            Frame frame = grabber.grabFrame();
+            if (frame != null) {
+                //视频快照
+                frame = grabber.grabImage();
+                BufferedImage bufferedImage = frameToBufferedImage(frame);
+                if (bufferedImage != null) {
+                    ImageIO.write(bufferedImage, IMAGE_FORMAT, file);
+                }
+                log.info("图片地址为[{}]", file.getAbsoluteFile());
+                grabber.stop();
+                MultipartFile multipartFile = getMultipartFile(file);
+                R<SysFile> upload = remoteFileService.upload(multipartFile);
+                if (upload.getCode() == HttpStatus.SUCCESS && upload.getData() != null) {
+                    return upload.getData();
+                }else {
+                    throw new ServerException(upload.getMsg());
+                }
+            }
+        }
+        return null;
+    }
+
+    private MultipartFile getMultipartFile(File file) {
+        try(FileInputStream fileInputStream = new FileInputStream(file)) {
+            return new MockMultipartFile(file.getName(),file.getName(),
+                    ContentType.APPLICATION_OCTET_STREAM.toString(),fileInputStream);
+        } catch (Exception e) {
+            throw new ServiceException(e.getMessage());
+        }
+    }
+}

+ 14 - 0
zd-modules/zd-forward/src/main/java/com/zd/forward/utils/VideoUtils.java

@@ -2,6 +2,10 @@ package com.zd.forward.utils;
 
 import lombok.extern.slf4j.Slf4j;
 import org.bytedeco.javacv.FFmpegFrameGrabber;
+import org.bytedeco.javacv.Frame;
+import org.bytedeco.javacv.Java2DFrameConverter;
+
+import java.awt.image.BufferedImage;
 
 /**
  * @author Administrator
@@ -34,4 +38,14 @@ public class VideoUtils {
         grabber.setFrameRate(FRAME_RATE);
         return grabber;
     }
+
+    /**
+     * frame 转图片流
+     */
+    public static BufferedImage frameToBufferedImage(Frame frame) {
+        //创建BufferedImage对象
+        try (Java2DFrameConverter converter = new Java2DFrameConverter()) {
+            return converter.getBufferedImage(frame);
+        }
+    }
 }

+ 1 - 0
zd-modules/zd-netty/src/main/java/com/zd/netty/sdk/DeJuRFIDServerImpl.java

@@ -103,6 +103,7 @@ public class DeJuRFIDServerImpl implements IService {
             // 订阅标签上报事件
             subscribeHandler(client, hardware);
             subscribeHandlerTagEpcOver(client,hardware);
+            subscribeTcpHandler(client);
             String serialNumber = client.getSerialNumber();
             if (StringUtils.hasLength(serialNumber)){
                 redisTemplate.opsForValue().set(serialNumber, hardware);