648540858
2023-02-22 019d95cfba07f0231bd5b385f6736883c6e90623
Merge branch 'wvp-28181-2.0'

# Conflicts:
# src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
41个文件已修改
1个文件已添加
681 ■■■■ 已修改文件
doc/_content/introduction/compile.md 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/ProxyServletConfig.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/SipPlatformRunner.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/SpringDocConfig.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/ThreadPoolTaskConfig.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/VersionConfig.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/redis/RedisConfig.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/task/SipRunner.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java 175 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/IDeviceChannelService.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/IDeviceService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorage.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/utils/UJson.java 150 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/MobilePosition/MobilePositionController.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/logback-spring-local.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/CloudRecordDetail.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/_content/introduction/compile.md
@@ -69,7 +69,7 @@
### 5.2 编译前端页面
```shell script
cd wvp-GB28181-pro/web_src/
npm --registry=https://registry.npm.taobao.org install
npm --registry=https://registry.npmmirror.com install
npm run build
```
编译如果报错, 一般都是网络问题, 导致的依赖包下载失败  
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
@@ -139,4 +139,15 @@
    public static final String WVP_STREAM_GB_ID_PREFIX = "memberNo_";
    public static final String WVP_STREAM_GPS_MSG_PREFIX = "WVP_STREAM_GPS_MSG_";
    /**
     * Redis Const
     * 设备录像信息结果前缀
     */
    public static final String REDIS_RECORD_INFO_RES_PRE = "GB_RECORD_INFO_RES_";
    /**
     * Redis Const
     * 设备录像信息结果前缀
     */
    public static final String REDIS_RECORD_INFO_RES_COUNT_PRE = "GB_RECORD_INFO_RES_COUNT:";
}
src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java
@@ -2,6 +2,7 @@
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.utils.DateUtil;
import org.junit.jupiter.api.Order;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
@@ -14,6 +15,7 @@
@Configuration("mediaConfig")
@Order(0)
public class MediaConfig{
    private final static Logger logger = LoggerFactory.getLogger(MediaConfig.class);
src/main/java/com/genersoft/iot/vmp/conf/ProxyServletConfig.java
@@ -5,6 +5,7 @@
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.junit.jupiter.api.Order;
import org.mitre.dsmiley.httpproxy.ProxyServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -25,6 +26,7 @@
 */
@SuppressWarnings(value = {"rawtypes", "unchecked"})
@Configuration
@Order(1)
public class ProxyServletConfig {
    private final static Logger logger = LoggerFactory.getLogger(ProxyServletConfig.class);
src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java
@@ -1,12 +1,14 @@
package com.genersoft.iot.vmp.conf;
import org.junit.jupiter.api.Order;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
@Component
@ConfigurationProperties(prefix = "sip", ignoreInvalidFields = true)
@Order(0)
public class SipConfig {
    private String ip;
src/main/java/com/genersoft/iot/vmp/conf/SipPlatformRunner.java
@@ -18,7 +18,7 @@
 * @author lin
 */
@Component
@Order(value=3)
@Order(value=13)
public class SipPlatformRunner implements CommandLineRunner {
    @Autowired
src/main/java/com/genersoft/iot/vmp/conf/SpringDocConfig.java
@@ -1,14 +1,11 @@
package com.genersoft.iot.vmp.conf;
import io.swagger.v3.oas.models.ExternalDocumentation;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.media.StringSchema;
import io.swagger.v3.oas.models.parameters.HeaderParameter;
import org.junit.jupiter.api.Order;
import org.springdoc.core.GroupedOpenApi;
import org.springdoc.core.SpringDocConfigProperties;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -17,6 +14,7 @@
 * @author lin
 */
@Configuration
@Order(1)
public class SpringDocConfig {
    @Value("${doc.enabled: true}")
src/main/java/com/genersoft/iot/vmp/conf/ThreadPoolTaskConfig.java
@@ -1,5 +1,6 @@
package com.genersoft.iot.vmp.conf;
import org.junit.jupiter.api.Order;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
@@ -12,6 +13,7 @@
 * @author lin
 */
@Configuration
@Order(1)
@EnableAsync(proxyTargetClass = true)
public class ThreadPoolTaskConfig {
src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
@@ -1,5 +1,6 @@
package com.genersoft.iot.vmp.conf;
import org.junit.jupiter.api.Order;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@@ -11,6 +12,7 @@
 */
@Component
@ConfigurationProperties(prefix = "user-settings", ignoreInvalidFields = true)
@Order(0)
public class UserSetting {
    private Boolean savePositionHistory = Boolean.FALSE;
src/main/java/com/genersoft/iot/vmp/conf/VersionConfig.java
@@ -1,10 +1,12 @@
package com.genersoft.iot.vmp.conf;
import org.junit.jupiter.api.Order;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "version")
@Order(0)
public class VersionConfig {
    private String version;
src/main/java/com/genersoft/iot/vmp/conf/redis/RedisConfig.java
@@ -8,6 +8,7 @@
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.PatternTopic;
@@ -22,6 +23,7 @@
 * 
 */
@Configuration
@Order(value=1)
public class RedisConfig extends CachingConfigurerSupport {
    @Autowired
src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
@@ -1,6 +1,7 @@
package com.genersoft.iot.vmp.conf.security;
import com.genersoft.iot.vmp.conf.UserSetting;
import org.junit.jupiter.api.Order;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -25,6 +26,7 @@
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Order(1)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    private final static Logger logger = LoggerFactory.getLogger(WebSecurityConfig.class);
src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
@@ -19,7 +19,7 @@
import java.util.concurrent.ConcurrentHashMap;
@Component
@Order(value=1)
@Order(value=10)
public class SipLayer implements CommandLineRunner {
    private final static Logger logger = LoggerFactory.getLogger(SipLayer.class);
src/main/java/com/genersoft/iot/vmp/gb28181/task/SipRunner.java
@@ -28,7 +28,7 @@
 * @author lin
 */
@Component
@Order(value=4)
@Order(value=14)
public class SipRunner implements CommandLineRunner {
    @Autowired
@@ -69,6 +69,26 @@
        // 重置cseq计数
        redisCatchStorage.resetAllCSEQ();
        // 清理redis
        // 清理数据库不存在但是redis中存在的数据
        List<Device> devicesInDb = deviceService.getAll();
        if (devicesInDb.size() == 0) {
            redisCatchStorage.removeAllDevice();
        }else {
            List<Device> devicesInRedis = redisCatchStorage.getAllDevices();
            if (devicesInRedis.size() > 0) {
                Map<String, Device> deviceMapInDb = new HashMap<>();
                devicesInDb.parallelStream().forEach(device -> {
                    deviceMapInDb.put(device.getDeviceId(), device);
                });
                devicesInRedis.parallelStream().forEach(device -> {
                    if (deviceMapInDb.get(device.getDeviceId()) == null) {
                        redisCatchStorage.removeDevice(device.getDeviceId());
                    }
                });
            }
        }
        // 查找国标推流
        List<SendRtpItem> sendRtpItems = redisCatchStorage.queryAllSendRTPServer();
        if (sendRtpItems.size() > 0) {
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
@@ -215,6 +215,25 @@
                        }else {
                            catalogXml.append("<Address>" + channel.getAddress() + "</Address>\r\n");
                        }
                        catalogXml.append("<Block>" + channel.getBlock() + "</Block>\r\n");
                        catalogXml.append("<SafetyWay>" + channel.getSafetyWay() + "</SafetyWay>\r\n");
                        catalogXml.append("<CertNum>" + channel.getCertNum() + "</CertNum>\r\n");
                        catalogXml.append("<Certifiable>" + channel.getCertifiable() + "</Certifiable>\r\n");
                        catalogXml.append("<ErrCode>" + channel.getErrCode() + "</ErrCode>\r\n");
                        catalogXml.append("<EndTime>" + channel.getEndTime() + "</EndTime>\r\n");
                        catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n");
                        catalogXml.append("<IPAddress>" + channel.getIpAddress() + "</IPAddress>\r\n");
                        catalogXml.append("<Port>" + channel.getPort() + "</Port>\r\n");
                        catalogXml.append("<Password>" + channel.getPort() + "</Password>\r\n");
                        catalogXml.append("<Status>" + (channel.getStatus() == 1?"ON":"OFF") + "</Status>\r\n");
                        catalogXml.append("<Longitude>" +
                                (channel.getLongitudeWgs84() != 0? channel.getLongitudeWgs84():channel.getLongitude())
                                + "</Longitude>\r\n");
                        catalogXml.append("<Latitude>" +
                                (channel.getLatitudeWgs84() != 0? channel.getLatitudeWgs84():channel.getLatitude())
                                + "</Latitude>\r\n");
                    }
                }
                catalogXml.append("</Item>\r\n");
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
@@ -360,7 +360,7 @@
                    return;
                }
                String username = sdp.getOrigin().getUsername();
                String addressStr = sdp.getOrigin().getAddress();
                String addressStr = sdp.getConnection().getAddress();
                logger.info("[上级点播]用户:{}, 通道:{}, 地址:{}:{}, ssrc:{}", username, channelId, addressStr, port, ssrc);
                Device device = null;
@@ -982,7 +982,7 @@
                    }
                    return;
                }
                String addressStr = sdp.getOrigin().getAddress();
                String addressStr = sdp.getConnection().getAddress();
                logger.info("设备{}请求语音流,地址:{}:{},ssrc:{}, {}", requesterId, addressStr, port, ssrc,
                        mediaTransmissionTCP ? (tcpActive? "TCP主动":"TCP被动") : "UDP");
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
@@ -38,6 +38,7 @@
import javax.sip.message.Response;
import java.text.ParseException;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
@@ -154,6 +155,17 @@
            Element deviceIdElement = rootElement.element("DeviceID");
            String channelId = deviceIdElement.getTextTrim().toString();
            Device device = redisCatchStorage.getDevice(deviceId);
            if (device == null) {
                // 根据通道id查询设备Id
                List<Device> deviceList = deviceChannelService.getDeviceByChannelId(channelId);
                if (deviceList.size() > 0) {
                    device = deviceList.get(0);
                }else {
                    logger.warn("[mobilePosition移动位置Notify] 未找到通道{}所属的设备", channelId);
                    return;
                }
            }
            if (device != null) {
                if (!ObjectUtils.isEmpty(device.getName())) {
                    mobilePosition.setDeviceName(device.getName());
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java
@@ -1,6 +1,5 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
import com.genersoft.iot.vmp.conf.ServiceInfo;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.gb28181.auth.DigestServerAuthenticationHelper;
@@ -95,7 +94,7 @@
//                }
//            }
            System.out.println(ServiceInfo.getServerPort());
//            System.out.println(ServiceInfo.getServerPort());
            SIPRequest request = (SIPRequest)evt.getRequest();
            Response response = null;
            boolean passwordCorrect = false;
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java
@@ -5,6 +5,7 @@
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import gov.nist.javax.sip.message.SIPRequest;
@@ -108,6 +109,7 @@
                                        continue;
                                    }
                                    DeviceChannel deviceChannel = XmlUtil.channelContentHander(itemDevice, device, null);
                                    deviceChannel = SipUtils.updateGps(deviceChannel, device.getGeoCoordSys());
                                    deviceChannel.setDeviceId(take.getDevice().getDeviceId());
                                    channelList.add(deviceChannel);
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java
@@ -1,16 +1,17 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.session.RecordDataCatch;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.utils.UJson;
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
import gov.nist.javax.sip.message.SIPRequest;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -26,11 +27,9 @@
import javax.sip.SipException;
import javax.sip.message.Response;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.stream.Collectors;
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
@@ -49,9 +48,6 @@
    private ResponseMessageHandler responseMessageHandler;
    @Autowired
    private RecordDataCatch recordDataCatch;
    @Autowired
    private DeferredResultHolder deferredResultHolder;
    @Autowired
@@ -61,6 +57,8 @@
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;
    private Long recordInfoTtl = 1800L;
    @Override
    public void afterPropertiesSet() throws Exception {
        responseMessageHandler.addHandler(cmdType, this);
@@ -68,93 +66,93 @@
    @Override
    public void handForDevice(RequestEvent evt, Device device, Element rootElement) {
        boolean isEmpty = taskQueue.isEmpty();
        try {
            // 回复200 OK
             responseAck((SIPRequest) evt.getRequest(), Response.OK);
        }catch (SipException | InvalidArgumentException | ParseException e) {
            logger.error("[命令发送失败] 国标级联 国标录像: {}", e.getMessage());
        }
        taskQueue.offer(new HandlerCatchData(evt, device, rootElement));
        if (isEmpty) {
            taskExecutor.execute(()->{
                while (!taskQueue.isEmpty()) {
                    try {
                        HandlerCatchData take = taskQueue.poll();
                        Element rootElementForCharset = getRootElement(take.getEvt(), take.getDevice().getCharset());
                        if (rootElement == null) {
                            logger.warn("[ 国标录像 ] content cannot be null, {}", evt.getRequest());
                            continue;
                        }
                        String sn = getText(rootElementForCharset, "SN");
                        String channelId = getText(rootElementForCharset, "DeviceID");
                        RecordInfo recordInfo = new RecordInfo();
                        recordInfo.setChannelId(channelId);
                        recordInfo.setDeviceId(take.getDevice().getDeviceId());
                        recordInfo.setSn(sn);
                        recordInfo.setName(getText(rootElementForCharset, "Name"));
                        String sumNumStr = getText(rootElementForCharset, "SumNum");
                        int sumNum = 0;
                        if (!ObjectUtils.isEmpty(sumNumStr)) {
                            sumNum = Integer.parseInt(sumNumStr);
                        }
                        recordInfo.setSumNum(sumNum);
                        Element recordListElement = rootElementForCharset.element("RecordList");
                        if (recordListElement == null || sumNum == 0) {
                            logger.info("无录像数据");
                            int count = recordDataCatch.put(take.getDevice().getDeviceId(),channelId, sn, sumNum, new ArrayList<>());
                            recordInfo.setCount(count);
                            eventPublisher.recordEndEventPush(recordInfo);
                            releaseRequest(take.getDevice().getDeviceId(), sn);
                        } else {
                            Iterator<Element> recordListIterator = recordListElement.elementIterator();
                            if (recordListIterator != null) {
                                List<RecordItem> recordList = new ArrayList<>();
                                // 遍历DeviceList
                                while (recordListIterator.hasNext()) {
                                    Element itemRecord = recordListIterator.next();
                                    Element recordElement = itemRecord.element("DeviceID");
                                    if (recordElement == null) {
                                        logger.info("记录为空,下一个...");
                                        continue;
                                    }
                                    RecordItem record = new RecordItem();
                                    record.setDeviceId(getText(itemRecord, "DeviceID"));
                                    record.setName(getText(itemRecord, "Name"));
                                    record.setFilePath(getText(itemRecord, "FilePath"));
                                    record.setFileSize(getText(itemRecord, "FileSize"));
                                    record.setAddress(getText(itemRecord, "Address"));
        taskExecutor.execute(()->{
            try {
                                    String startTimeStr = getText(itemRecord, "StartTime");
                                    record.setStartTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(startTimeStr));
                                    String endTimeStr = getText(itemRecord, "EndTime");
                                    record.setEndTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(endTimeStr));
                                    record.setSecrecy(itemRecord.element("Secrecy") == null ? 0
                                            : Integer.parseInt(getText(itemRecord, "Secrecy")));
                                    record.setType(getText(itemRecord, "Type"));
                                    record.setRecorderId(getText(itemRecord, "RecorderID"));
                                    recordList.add(record);
                                }
                                recordInfo.setRecordList(recordList);
                                int count = recordDataCatch.put(take.getDevice().getDeviceId(),channelId, sn, sumNum, recordList);recordInfo.setCount(count);
                                logger.info("[国标录像], {}->{}: {}/{}", take.getDevice().getDeviceId(), sn, count, sumNum);
                                // 发送消息,如果是上级查询此录像,则会通过这里通知给上级
                                eventPublisher.recordEndEventPush(recordInfo);
                String sn = getText(rootElement, "SN");
                String channelId = getText(rootElement, "DeviceID");
                RecordInfo recordInfo = new RecordInfo();
                recordInfo.setChannelId(channelId);
                recordInfo.setDeviceId(device.getDeviceId());
                recordInfo.setSn(sn);
                recordInfo.setName(getText(rootElement, "Name"));
                String sumNumStr = getText(rootElement, "SumNum");
                int sumNum = 0;
                if (!ObjectUtils.isEmpty(sumNumStr)) {
                    sumNum = Integer.parseInt(sumNumStr);
                }
                recordInfo.setSumNum(sumNum);
                Element recordListElement = rootElement.element("RecordList");
                if (recordListElement == null || sumNum == 0) {
                    logger.info("无录像数据");
                    recordInfo.setCount(sumNum);
                    eventPublisher.recordEndEventPush(recordInfo);
                    releaseRequest(device.getDeviceId(), sn,recordInfo);
                } else {
                    Iterator<Element> recordListIterator = recordListElement.elementIterator();
                    if (recordListIterator != null) {
                        List<RecordItem> recordList = new ArrayList<>();
                        // 遍历DeviceList
                        while (recordListIterator.hasNext()) {
                            Element itemRecord = recordListIterator.next();
                            Element recordElement = itemRecord.element("DeviceID");
                            if (recordElement == null) {
                                logger.info("记录为空,下一个...");
                                continue;
                            }
                            if (recordDataCatch.isComplete(take.getDevice().getDeviceId(), sn)){
                                releaseRequest(take.getDevice().getDeviceId(), sn);
                            }
                            RecordItem record = new RecordItem();
                            record.setDeviceId(getText(itemRecord, "DeviceID"));
                            record.setName(getText(itemRecord, "Name"));
                            record.setFilePath(getText(itemRecord, "FilePath"));
                            record.setFileSize(getText(itemRecord, "FileSize"));
                            record.setAddress(getText(itemRecord, "Address"));
                            String startTimeStr = getText(itemRecord, "StartTime");
                            record.setStartTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(startTimeStr));
                            String endTimeStr = getText(itemRecord, "EndTime");
                            record.setEndTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(endTimeStr));
                            record.setSecrecy(itemRecord.element("Secrecy") == null ? 0
                                    : Integer.parseInt(getText(itemRecord, "Secrecy")));
                            record.setType(getText(itemRecord, "Type"));
                            record.setRecorderId(getText(itemRecord, "RecorderID"));
                            recordList.add(record);
                        }
                    } catch (DocumentException e) {
                        logger.error("xml解析异常: ", e);
                    } catch (Exception e) {
                        logger.warn("[国标录像] 发现未处理的异常, {}\r\n{}",e.getMessage(), evt.getRequest());
                        Map<String, String> map = recordList.stream()
                                .filter(record -> record.getDeviceId() != null)
                                .collect(Collectors.toMap(record -> record.getStartTime()+ record.getEndTime(), UJson::writeJson));
                        // 获取任务结果数据
                        String resKey = VideoManagerConstants.REDIS_RECORD_INFO_RES_PRE + channelId + sn;
                        RedisUtil.hmset(resKey, map, recordInfoTtl);
                        String resCountKey = VideoManagerConstants.REDIS_RECORD_INFO_RES_COUNT_PRE + channelId + sn;
                        long incr = RedisUtil.incr(resCountKey, map.size());
                        RedisUtil.expire(resCountKey, recordInfoTtl);
                        recordInfo.setRecordList(recordList);
                        recordInfo.setCount(Math.toIntExact(incr));
                        eventPublisher.recordEndEventPush(recordInfo);
                        if (incr < sumNum) {
                            return;
                        }
                        // 已接收完成
                        List<RecordItem> resList = RedisUtil.hmget(resKey).values().stream().map(e -> UJson.readJson(e.toString(), RecordItem.class)).collect(Collectors.toList());
                        if (resList.size() < sumNum) {
                            return;
                        }
                        recordInfo.setRecordList(resList);
                        releaseRequest(device.getDeviceId(), sn,recordInfo);
                    }
                }
            });
        }
            } catch (Exception e) {
                logger.error("[国标录像] 发现未处理的异常, "+e.getMessage(), e);
            }
        });
    }
    @Override
@@ -162,15 +160,14 @@
    }
    public void releaseRequest(String deviceId, String sn){
    public void releaseRequest(String deviceId, String sn,RecordInfo recordInfo){
        String key = DeferredResultHolder.CALLBACK_CMD_RECORDINFO + deviceId + sn;
        // 对数据进行排序
        Collections.sort(recordDataCatch.getRecordInfo(deviceId, sn).getRecordList());
        Collections.sort(recordInfo.getRecordList());
        RequestMessage msg = new RequestMessage();
        msg.setKey(key);
        msg.setData(recordDataCatch.getRecordInfo(deviceId, sn));
        msg.setData(recordInfo);
        deferredResultHolder.invokeAllResult(msg);
        recordDataCatch.remove(deviceId, sn);
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java
@@ -80,8 +80,8 @@
     */
    @Override
    public void process(ResponseEvent evt ){
        logger.debug("接收到消息:" + evt.getResponse());
        try {
            SIPResponse response = (SIPResponse)evt.getResponse();
            int statusCode = response.getStatusCode();
            // trying不会回复
src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java
@@ -1,5 +1,6 @@
package com.genersoft.iot.vmp.gb28181.utils;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.RemoteAddressInfo;
import com.genersoft.iot.vmp.utils.GitUtil;
import gov.nist.javax.sip.address.AddressImpl;
@@ -168,4 +169,37 @@
        return new RemoteAddressInfo(remoteAddress, remotePort);
    }
    public static DeviceChannel updateGps(DeviceChannel deviceChannel, String geoCoordSys) {
        if (deviceChannel.getLongitude()*deviceChannel.getLatitude() > 0) {
            if (geoCoordSys == null) {
                geoCoordSys = "WGS84";
            }
            if ("WGS84".equals(geoCoordSys)) {
                deviceChannel.setLongitudeWgs84(deviceChannel.getLongitude());
                deviceChannel.setLatitudeWgs84(deviceChannel.getLatitude());
                Double[] position = Coordtransform.WGS84ToGCJ02(deviceChannel.getLongitude(), deviceChannel.getLatitude());
                deviceChannel.setLongitudeGcj02(position[0]);
                deviceChannel.setLatitudeGcj02(position[1]);
            }else if ("GCJ02".equals(geoCoordSys)) {
                deviceChannel.setLongitudeGcj02(deviceChannel.getLongitude());
                deviceChannel.setLatitudeGcj02(deviceChannel.getLatitude());
                Double[] position = Coordtransform.GCJ02ToWGS84(deviceChannel.getLongitude(), deviceChannel.getLatitude());
                deviceChannel.setLongitudeWgs84(position[0]);
                deviceChannel.setLatitudeWgs84(position[1]);
            }else {
                deviceChannel.setLongitudeGcj02(0.00);
                deviceChannel.setLatitudeGcj02(0.00);
                deviceChannel.setLongitudeWgs84(0.00);
                deviceChannel.setLatitudeWgs84(0.00);
            }
        }else {
            deviceChannel.setLongitudeGcj02(deviceChannel.getLongitude());
            deviceChannel.setLatitudeGcj02(deviceChannel.getLatitude());
            deviceChannel.setLongitudeWgs84(deviceChannel.getLongitude());
            deviceChannel.setLatitudeWgs84(deviceChannel.getLatitude());
        }
        return deviceChannel;
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
@@ -1,11 +1,9 @@
package com.genersoft.iot.vmp.gb28181.utils;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.TreeType;
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
import com.genersoft.iot.vmp.utils.DateUtil;
import org.dom4j.Attribute;
@@ -400,6 +398,7 @@
        } else {
            deviceChannel.setLatitude(0.00);
        }
        deviceChannel.setGpsTime(DateUtil.getNow());
@@ -414,6 +413,7 @@
        } else {
            deviceChannel.setPTZType(Integer.parseInt(XmlUtil.getText(itemDevice, "PTZType")));
        }
        return deviceChannel;
    }
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java
@@ -25,7 +25,7 @@
import java.util.concurrent.ConcurrentHashMap;
@Component
@Order(value=2)
@Order(value=12)
public class ZLMRunner implements CommandLineRunner {
    private final static Logger logger = LoggerFactory.getLogger(ZLMRunner.class);
src/main/java/com/genersoft/iot/vmp/service/IDeviceChannelService.java
@@ -46,4 +46,14 @@
     * @return
     */
    List<ChannelReduce> queryAllChannelList(String platformId);
    /**
     * 数据位置信息格式处理
     */
    boolean updateAllGps(Device device);
    /**
     * 查询通道所属的设备
     */
    List<Device> getDeviceByChannelId(String channelId);
}
src/main/java/com/genersoft/iot/vmp/service/IDeviceService.java
@@ -163,4 +163,8 @@
     */
    ResourceBaceInfo getOverview();
    /**
     * 获取所有设备
     */
    List<Device> getAll();
}
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java
@@ -19,6 +19,7 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
 * @author lin
@@ -176,5 +177,36 @@
        return channelMapper.queryChannelListInAll(null, null, null, platformId, null);
    }
    @Override
    public boolean updateAllGps(Device device) {
        List<DeviceChannel> deviceChannels = channelMapper.getChannelsWithoutTransform(device.getDeviceId());
        List<DeviceChannel> result = new CopyOnWriteArrayList<>();
        if (deviceChannels.size() == 0) {
            return true;
        }
        String now = DateUtil.getNow();
        deviceChannels.parallelStream().forEach(deviceChannel -> {
            deviceChannel.setUpdateTime(now);
            result.add(updateGps(deviceChannel, device));
        });
        int limitCount = 300;
        if (result.size() > limitCount) {
            for (int i = 0; i < result.size(); i += limitCount) {
                int toIndex = i + limitCount;
                if (i + limitCount > result.size()) {
                    toIndex = result.size();
                }
                channelMapper.batchUpdate(result.subList(i, toIndex));
            }
        }else {
            channelMapper.batchUpdate(result);
        }
        return true;
    }
    @Override
    public List<Device> getDeviceByChannelId(String channelId) {
        return channelMapper.getDeviceByChannelId(channelId);
    }
}
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
@@ -655,4 +655,9 @@
    public ResourceBaceInfo getOverview() {
        return deviceMapper.getOverview();
    }
    @Override
    public List<Device> getAll() {
        return deviceMapper.getAll();
    }
}
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java
@@ -366,7 +366,7 @@
        // 存储数据到stream_push表
        streamPushMapper.addAll(streamPushItems);
        List<StreamPushItem> streamPushItemForGbStream = streamPushItems.stream()
                .filter(streamPushItem-> streamPushItem.getId() != null)
                .filter(streamPushItem-> streamPushItem.getGbId() != null)
                .collect(Collectors.toList());
        // 存储数据到gb_stream表, id会返回到streamPushItemForGbStream里
        if (streamPushItemForGbStream.size() > 0) {
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
@@ -258,4 +258,7 @@
    List<SendRtpItem> queryAllSendRTPServer();
    List<Device> getAllDevices();
    void removeAllDevice();
}
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorage.java
@@ -56,7 +56,7 @@
     * @param count 每页数量
     * @return
     */
    public PageInfo queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, Boolean online, Boolean catalogUnderDevice, int page, int count);
    public PageInfo<DeviceChannel> queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, Boolean online, Boolean catalogUnderDevice, int page, int count);
    
    public List<DeviceChannel> queryChannelsByDeviceIdWithStartAndLimit(String deviceId, String query, Boolean hasSubChannel, Boolean online, int start, int limit,List<String> channelIds);
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
@@ -1,5 +1,6 @@
package com.genersoft.iot.vmp.storager.dao;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannelInPlatform;
import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo;
@@ -357,4 +358,21 @@
    @Select("select count(1) as total, sum(status) as online from device_channel")
    ResourceBaceInfo getOverview();
    @Select("select channelId" +
            ", deviceId" +
            ", latitude" +
            ", longitude" +
            ", latitudeWgs84" +
            ", longitudeWgs84" +
            ", latitudeGcj02" +
            ", longitudeGcj02 " +
            "from device_channel where deviceId = #{deviceId} " +
            "and latitude != 0 " +
            "and  longitude != 0 " +
            "and (latitudeGcj02 = 0 or latitudeWgs84 = 0 or longitudeWgs84 = 0 or longitudeGcj02 = 0)")
    List<DeviceChannel> getChannelsWithoutTransform(String deviceId);
    @Select("select de.* from device de left join device_channel dc on de.deviceId = dc.deviceId where dc.channelId=#{channelId}")
    List<Device> getDeviceByChannelId(String channelId);
}
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java
@@ -280,4 +280,6 @@
    @Select("select count(1) as total, sum(online) as online from device")
    ResourceBaceInfo getOverview();
    @Select("select * from device")
    List<Device> getAll();
}
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
@@ -665,6 +665,31 @@
    }
    @Override
    public void removeAllDevice() {
        String scanKey = VideoManagerConstants.DEVICE_PREFIX + userSetting.getServerId() + "_*";
        List<Object> keys = RedisUtil.scan(scanKey);
        for (Object key : keys) {
            RedisUtil.del((String) key);
        }
    }
    @Override
    public List<Device> getAllDevices() {
        String scanKey = VideoManagerConstants.DEVICE_PREFIX + userSetting.getServerId() + "_*";
        List<Device> result = new ArrayList<>();
        List<Object> keys = RedisUtil.scan(scanKey);
        for (Object o : keys) {
            String key = (String) o;
            Device device = JsonUtil.redisJsonToObject(key, Device.class);
            if (Objects.nonNull(device)) { // 只取没有存过得
                result.add(JsonUtil.redisJsonToObject(key, Device.class));
            }
        }
        return result;
    }
    @Override
    public Device getDevice(String deviceId) {
        String key = VideoManagerConstants.DEVICE_PREFIX + userSetting.getServerId() + "_" + deviceId;
        return JsonUtil.redisJsonToObject(key, Device.class);
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
@@ -226,8 +226,10 @@
                    if (allChannelMap.containsKey(deviceChannel.getChannelId())) {
                        deviceChannel.setStreamId(allChannelMap.get(deviceChannel.getChannelId()).getStreamId());
                        deviceChannel.setHasAudio(allChannelMap.get(deviceChannel.getChannelId()).isHasAudio());
                        deviceChannel.setUpdateTime(DateUtil.getNow());
                        updateChannels.add(deviceChannel);
                    }else {
                        deviceChannel.setCreateTime(DateUtil.getNow());
                        addChannels.add(deviceChannel);
                    }
                    if (!ObjectUtils.isEmpty(deviceChannel.getParentId())) {
src/main/java/com/genersoft/iot/vmp/utils/UJson.java
New file
@@ -0,0 +1,150 @@
package com.genersoft.iot.vmp.utils;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
/**
 * @author gaofuwang
 * @version 1.0
 * @date 2022/3/11 10:17
 */
public class UJson {
    private static Logger logger = LoggerFactory.getLogger(UJson.class);
    public static final ObjectMapper JSON_MAPPER = new ObjectMapper();
    static {
        JSON_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
    }
    private ObjectNode node;
    public UJson(){
        this.node = JSON_MAPPER.createObjectNode();
    }
    public UJson(String json){
        if(StringUtils.isBlank(json)){
            this.node = JSON_MAPPER.createObjectNode();
        }else{
            try {
                this.node = JSON_MAPPER.readValue(json, ObjectNode.class);
            }catch (Exception e){
                logger.error(e.getMessage(), e);
                this.node = JSON_MAPPER.createObjectNode();
            }
        }
    }
    public UJson(ObjectNode node){
        this.node = node;
    }
    public String asText(String key){
        JsonNode jsonNode = node.get(key);
        if(Objects.isNull(jsonNode)){
            return "";
        }
        return jsonNode.asText();
    }
    public String asText(String key, String defaultVal){
        JsonNode jsonNode = node.get(key);
        if(Objects.isNull(jsonNode)){
            return "";
        }
        return jsonNode.asText(defaultVal);
    }
    public UJson put(String key, String value){
        this.node.put(key, value);
        return this;
    }
    public UJson put(String key, Integer value){
        this.node.put(key, value);
        return this;
    }
    public static UJson json(){
        return new UJson();
    }
    public static UJson json(String json){
        return new UJson(json);
    }
    public static <T> T readJson(String json, Class<T> clazz){
        if(StringUtils.isBlank(json)){
            return null;
        }
        try {
            return JSON_MAPPER.readValue(json, clazz);
        }catch (Exception e){
            logger.error(e.getMessage(), e);
            return null;
        }
    }
    public static String writeJson(Object object) {
        try{
            return JSON_MAPPER.writeValueAsString(object);
        }catch (Exception e){
            logger.error(e.getMessage(), e);
            return "";
        }
    }
    @Override
    public String toString() {
        return node.toString();
    }
    public int asInt(String key, int defValue) {
        JsonNode jsonNode = this.node.get(key);
        if(Objects.isNull(jsonNode)){
            return defValue;
        }
        return jsonNode.asInt(defValue);
    }
    public UJson getSon(String key) {
        JsonNode sonNode = this.node.get(key);
        if(Objects.isNull(sonNode)){
            return new UJson();
        }
        return new UJson((ObjectNode) sonNode);
    }
    public UJson set(String key, ObjectNode sonNode) {
        this.node.set(key, sonNode);
        return this;
    }
    public UJson set(String key, UJson sonNode) {
        this.node.set(key, sonNode.node);
        return this;
    }
    public Iterator<Map.Entry<String, JsonNode>> fields() {
        return this.node.fields();
    }
    public ObjectNode getNode() {
        return this.node;
    }
    public UJson setAll(UJson json) {
        this.node.setAll(json.node);
        return this;
    }
}
src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java
@@ -238,7 +238,7 @@
     * @param time 时间
     * @return true / false
     */
    public static boolean hmset(String key, Map<Object, Object> map, long time) {
    public static boolean hmset(String key, Map<?, ?> map, long time) {
        if (redisTemplate == null) {
            redisTemplate = SpringBeanFactory.getBean("redisTemplate");
        }
src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java
@@ -1,43 +1,96 @@
package com.genersoft.iot.vmp.vmanager.bean;
import com.genersoft.iot.vmp.common.StreamInfo;
import io.swagger.v3.oas.annotations.media.Schema;
@Schema(description = "流信息")
public class StreamContent {
    @Schema(description = "应用名")
    private String app;
    @Schema(description = "流ID")
    private String stream;
    @Schema(description = "IP")
    private String ip;
    @Schema(description = "HTTP-FLV流地址")
    private String flv;
    @Schema(description = "HTTPS-FLV流地址")
    private String https_flv;
    @Schema(description = "Websocket-FLV流地址")
    private String ws_flv;
    @Schema(description = "Websockets-FLV流地址")
    private String wss_flv;
    @Schema(description = "HTTP-FMP4流地址")
    private String fmp4;
    @Schema(description = "HTTPS-FMP4流地址")
    private String https_fmp4;
    @Schema(description = "Websocket-FMP4流地址")
    private String ws_fmp4;
    @Schema(description = "Websockets-FMP4流地址")
    private String wss_fmp4;
    @Schema(description = "HLS流地址")
    private String hls;
    @Schema(description = "HTTPS-HLS流地址")
    private String https_hls;
    @Schema(description = "Websocket-HLS流地址")
    private String ws_hls;
    @Schema(description = "Websockets-HLS流地址")
    private String wss_hls;
    @Schema(description = "HTTP-TS流地址")
    private String ts;
    @Schema(description = "HTTPS-TS流地址")
    private String https_ts;
    @Schema(description = "Websocket-TS流地址")
    private String ws_ts;
    @Schema(description = "Websockets-TS流地址")
    private String wss_ts;
    @Schema(description = "RTMP流地址")
    private String rtmp;
    @Schema(description = "RTMPS流地址")
    private String rtmps;
    @Schema(description = "RTSP流地址")
    private String rtsp;
    @Schema(description = "RTSPS流地址")
    private String rtsps;
    @Schema(description = "RTC流地址")
    private String rtc;
    @Schema(description = "RTCS流地址")
    private String rtcs;
    @Schema(description = "流媒体ID")
    private String mediaServerId;
    @Schema(description = "流编码信息")
    private Object tracks;
    @Schema(description = "开始时间")
    private String startTime;
    @Schema(description = "结束时间")
    private String endTime;
    private double progress;
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/MobilePosition/MobilePositionController.java
@@ -1,39 +1,30 @@
package com.genersoft.iot.vmp.vmanager.gb28181.MobilePosition;
import java.text.ParseException;
import java.util.List;
import java.util.UUID;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.MobilePosition;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import com.genersoft.iot.vmp.service.IDeviceChannelService;
import com.genersoft.iot.vmp.service.IDeviceService;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import com.github.pagehelper.util.StringUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;
import javax.sip.InvalidArgumentException;
import javax.sip.SipException;
import java.text.ParseException;
import java.util.List;
import java.util.UUID;
/**
 *  位置信息管理
@@ -57,6 +48,9 @@
    @Autowired
    private IDeviceService deviceService;
    @Autowired
    private IDeviceChannelService deviceChannelService;
    /**
     * 查询历史轨迹
@@ -162,4 +156,24 @@
            throw new ControllerException(ErrorCode.ERROR100);
        }
    }
    /**
     * 数据位置信息格式处理
     * @param deviceId 设备ID
     * @return true = 命令发送成功
     */
    @Operation(summary = "数据位置信息格式处理")
    @Parameter(name = "deviceId", description = "设备国标编号", required = true)
    @GetMapping("/transform/{deviceId}")
    public void positionTransform(@PathVariable String deviceId) {
        Device device = deviceService.getDevice(deviceId);
        if (device == null) {
            throw new ControllerException(ErrorCode.ERROR400.getCode(), "未找到设备: " + deviceId);
        }
        boolean result = deviceChannelService.updateAllGps(device);
        if (!result) {
            throw new ControllerException(ErrorCode.ERROR100);
        }
    }
}
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
@@ -123,7 +123,7 @@
    @Parameter(name = "online", description = "是否在线")
    @Parameter(name = "channelType", description = "设备/子目录-> false/true")
    @Parameter(name = "catalogUnderDevice", description = "是否直属与设备的目录")
    public PageInfo channels(@PathVariable String deviceId,
    public PageInfo<DeviceChannel> channels(@PathVariable String deviceId,
                                               int page, int count,
                                               @RequestParam(required = false) String query,
                                               @RequestParam(required = false) Boolean online,
@@ -223,7 +223,7 @@
    @Parameter(name = "online", description = "是否在线")
    @Parameter(name = "channelType", description = "设备/子目录-> false/true")
    @GetMapping("/sub_channels/{deviceId}/{channelId}/channels")
    public PageInfo subChannels(@PathVariable String deviceId,
    public PageInfo<DeviceChannel> subChannels(@PathVariable String deviceId,
                                                  @PathVariable String channelId,
                                                  int page,
                                                  int count,
@@ -237,8 +237,7 @@
            return deviceChannelPageResult;
        }
        PageInfo pageResult = storager.querySubChannels(deviceId, channelId, query, channelType, online, page, count);
        return pageResult;
        return storager.querySubChannels(deviceId, channelId, query, channelType, online, page, count);
    }
    /**
src/main/resources/logback-spring-local.xml
@@ -4,7 +4,7 @@
    <springProperty scop="context" name="spring.application.name" source="spring.application.name" defaultValue=""/>
    <property name="LOG_HOME" value="logs" />
    <substitutionProperty name="log.pattern" value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(---){faint} %clr(%-80.80logger{79}){cyan} %clr(:){faint} %m%n%wEx"/>
    <substitutionProperty name="log.pattern" value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(---){faint} %clr(%-1.30logger{0}){cyan} %clr(:){faint} %m%n%wEx"/>
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
    <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
web_src/src/components/CloudRecordDetail.vue
@@ -115,7 +115,7 @@
    props: ['recordFile', 'mediaServerId', 'dateFiles', 'mediaServerPath'],
        data() {
            return {
        basePath: `${this.mediaServerPath}/record`,
        basePath: `${this.mediaServerPath}`,
              dateFilesObj: [],
              detailFiles: [],
        chooseDate: null,