gb28181 MANSCDP+xml 编解码

This commit is contained in:
shikong 2023-09-24 21:31:09 +08:00
parent 2550500fb9
commit 4e62e90c0c
8 changed files with 507 additions and 0 deletions

View File

@ -0,0 +1,18 @@
package cn.skcks.docking.gb28181.constant;
@SuppressWarnings("unused")
public class CmdType {
public static final String KEEPALIVE = "Keepalive";
public static final String DEVICE_CONFIG = "DeviceConfig";
public static final String DEVICE_CONTROL = "DeviceControl";
public static final String DEVICE_STATUS = "DeviceStatus";
public static final String CATALOG = "Catalog";
public static final String ALARM = "Alarm";
public static final String MOBILE_POSITION = "MobilePosition";
public static final String BROADCAST = "Broadcast";
public static final String DEVICE_INFO = "DeviceInfo";
public static final String RECORD_INFO = "RecordInfo";
public static final String MEDIA_STATUS = "MediaStatus";
public static final String CONFIG_DOWNLOAD = "ConfigDownload";
public static final String PRESET_QUERY = "PresetQuery";
}

View File

@ -7,6 +7,8 @@ public class GB28181Constant {
public static final String CHARSET = "GB2312";
public static final String GEO_COORD_SYS = "WGS84";
public static final String DATETIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss";
public static class TransPort {
public static final String UDP = ListeningPoint.UDP;
public static final String TCP = ListeningPoint.TCP;

View File

@ -0,0 +1,22 @@
package cn.skcks.docking.gb28181.sip.manscdp.catalog;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@JacksonXmlRootElement(localName = "DeviceList")
@AllArgsConstructor
@NoArgsConstructor
@Data
public class CatalogDeviceListDTO {
@JacksonXmlProperty(isAttribute = true)
private Integer num;
@JacksonXmlProperty(localName = "Item")
@JacksonXmlElementWrapper(useWrapping = false)
private List<CatalogItemDTO> deviceList;
}

View File

@ -0,0 +1,150 @@
package cn.skcks.docking.gb28181.sip.manscdp.catalog;
import cn.skcks.docking.gb28181.constant.GB28181Constant;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@JacksonXmlRootElement(localName = "Item")
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class CatalogItemDTO {
/**
* 设备/区域/系统编码(必选)
*/
@JacksonXmlProperty(localName = "DeviceID")
private String deviceId;
/**
* 设备/区域/系统名称(必选)
*/
private String name;
/**
* 当为设备时,设备厂商(必选)
*/
private String manufacturer;
/**
* 当为设备时,设备型号(必选)
*/
private String model;
/**
* 当为设备时,设备归属(必选)
*/
private String owner;
/**
* 行政区域(必选)
*/
@JacksonXmlProperty(localName = "CivilCode")
private String civilCode;
/**
* 警区(可选)
*/
private String block;
/**
* 当为设备时,安装地址(必选)
*/
private String address;
/**
* 当为设备时,是否有子设备(必选)1有, 0没有
*/
@Builder.Default
private Integer parental = 0;
/**
* 父设备/区域/系统ID(必选)
*/
@JacksonXmlProperty(localName = "ParentID")
private String parentId;
/**
* 信令安全模式(可选)缺省为0; 0:不采用;2:S/MIME 签名方式;3:S/ MIME加密签名同时采用方式;4:数字摘要方式
*/
@Builder.Default
private Integer safetyWay = 0;
/**
* 注册方式(必选)缺省为1;1:符合IETF RFC3261标准的认证注册模 ;2:基于口令的双向认证注册模式;3:基于数字证书的双向认证注册模式
*/
@Builder.Default
private Integer registerWay = 1;
/**
* 证书序列号(有证书的设备必选)
*/
private String certNum;
/**
* 证书有效标识(有证书的设备必选)缺省为0;证书有效标识:0:无效 1: 有效
*/
@Builder.Default
private Integer certifiable = 0;
/**
* 无效原因码(有证书且证书无效的设备必选)
*/
@Builder.Default
private Integer errCode = 0;
/**
* 证书终止有效期(有证书的设备必选)
*/
@JsonFormat(pattern = GB28181Constant.DATETIME_FORMAT, timezone = GB28181Constant.TIME_ZONE)
private Date endTime;
/**
* 保密属性(必选)缺省为0;0:不涉密,1:涉密
*/
@Builder.Default
private Integer secrecy = 0;
/**
* 设备/区域/系统IP地址(可选)
*/
@JacksonXmlProperty(localName = "IPAddress")
private String ipAddress;
/**
* 设备/区域/系统端口(可选)
*/
private Integer port;
/**
* 设备口令(可选)
*/
private String password;
/**
* 设备状态(必选)
*/
@Builder.Default
private String status = "ON";
/**
* 经度(可选)
*/
@Builder.Default
private String longitude = "0.0";
/**
* 纬度(可选)
*/
@Builder.Default
private String latitude = "0.0";
}

View File

@ -0,0 +1,30 @@
package cn.skcks.docking.gb28181.sip.manscdp.catalog;
import cn.skcks.docking.gb28181.constant.CmdType;
import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@JacksonXmlRootElement(localName = "Query")
@JsonRootName("Query")
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class CatalogQueryDTO {
@Builder.Default
private String cmdType = CmdType.CATALOG;
@JacksonXmlProperty(localName = "SN")
private String sn;
/**
* 目标设备的设备编码(必选)
*/
@JacksonXmlProperty(localName = "DeviceID")
private String deviceId;
}

View File

@ -0,0 +1,31 @@
package cn.skcks.docking.gb28181.sip.manscdp.catalog;
import cn.skcks.docking.gb28181.constant.CmdType;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@JacksonXmlRootElement(localName = "Response")
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Data
public class CatalogResponseDTO {
@Builder.Default
private String cmdType = CmdType.CATALOG;
@JacksonXmlProperty(localName = "SN")
private String sn;
/**
* 目标设备的设备编码(必选)
*/
@JacksonXmlProperty(localName = "DeviceID")
private String deviceId;
private Long sumNum;
private CatalogDeviceListDTO deviceList;
}

View File

@ -0,0 +1,186 @@
package cn.skcks.docking.gb28181.sip.utils;
import cn.skcks.docking.gb28181.constant.GB28181Constant;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.json.JsonReadFeature;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
import lombok.*;
import java.nio.charset.Charset;
import java.util.Objects;
@SuppressWarnings("unused")
public class MANSCDPUtils {
private static final XmlMapper mapper = new XmlMapper();
static {
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
// 如果json中有新增的字段并且是实体类类中不存在的不报错
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false);
// 允许出现特殊字符和转义符
mapper.configure(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature(), true);
// 允许出现单引号
mapper.configure(JsonReadFeature.ALLOW_SINGLE_QUOTES.mappedFeature(), true);
// 大驼峰 (首字母大写)
mapper.setPropertyNamingStrategy(new PropertyNamingStrategies.UpperCamelCaseStrategy());
// 添加 xml 头部声明
mapper.configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, false);
mapper.configure(ToXmlGenerator.Feature.UNWRAP_ROOT_OBJECT_NODE, true);
}
@JacksonXmlRootElement(localName = "xml")
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public static class XMLWrapper<T> {
@Builder.Default
@JacksonXmlProperty(isAttribute = true, localName = "encoding")
private String encoding = GB28181Constant.CHARSET;
@JsonInclude(JsonInclude.Include.NON_NULL)
private T query;
@JsonInclude(JsonInclude.Include.NON_NULL)
private T response;
@JsonInclude(JsonInclude.Include.NON_NULL)
private T notify;
@JsonInclude(JsonInclude.Include.NON_NULL)
private T control;
}
public static String toXml(Object obj, String inputCharset,String outputCharset) {
try {
return new String(Objects.requireNonNull(toByteXml(obj, inputCharset)), Charset.forName(outputCharset));
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static String toXml(Object obj, String charset) {
if(obj == null){
return null;
}
try {
return new String(toByteXml(obj, GB28181Constant.CHARSET), Charset.forName(charset));
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static String toXml(Object obj) {
if(obj == null){
return null;
}
try {
return new String(toByteXml(obj, GB28181Constant.CHARSET), GB28181Constant.CHARSET);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static byte[] toByteXml(Object obj) {
try {
return toByteXml(obj, GB28181Constant.CHARSET);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static byte[] toByteXml(Object obj, Charset charset) {
try {
return mapper.writeValueAsString(obj).getBytes(charset);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static byte[] toByteXml(Object obj, String charset) {
if(obj == null){
return null;
}
try {
return mapper.writeValueAsString(obj).getBytes(Charset.forName(charset));
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
@SneakyThrows
public static <T> T parse(byte[] xml, Class<T> clazz) {
return parse(xml, clazz, GB28181Constant.CHARSET);
}
public static <T> T parse(byte[] xml, Class<T> clazz, String charset) {
return parse(xml, clazz, Charset.forName(charset));
}
public static <T> T parse(byte[] xml, Class<T> clazz, Charset charset) {
return parse(new String(xml, charset), clazz);
}
public static <T> T parse(String xml, Class<T> clazz) {
try {
return mapper.readValue(xml, clazz);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
@SneakyThrows
public static <T> T parse(byte[] xml, TypeReference<T> clazz) {
return parse(xml, clazz, GB28181Constant.CHARSET);
}
public static <T> T parse(byte[] xml, TypeReference<T> clazz, String charset) {
return parse(xml, clazz, Charset.forName(charset));
}
public static <T> T parse(byte[] xml, TypeReference<T> clazz, Charset charset) {
return parse(new String(xml, charset), clazz);
}
public static <T> T parse(String xml, TypeReference<T> clazz) {
try {
return mapper.readValue(xml, clazz);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static <T> T convert(Object object, Class<T> clazz) {
return MANSCDPUtils.convert(object, clazz, GB28181Constant.CHARSET);
}
@SneakyThrows
public static <T> T convert(Object object, Class<T> clazz, String charset) {
return MANSCDPUtils.convert(object, clazz, Charset.forName(charset));
}
@SneakyThrows
public static <T> T convert(Object object, Class<T> clazz, Charset charset) {
if(object == null){
return null;
}
return MANSCDPUtils.parse(MANSCDPUtils.toXml(object).getBytes(charset), clazz, charset);
}
}

View File

@ -0,0 +1,68 @@
package cn.skcks.docking.gb28181.sip.manscdp;
import cn.skcks.docking.gb28181.sip.manscdp.catalog.CatalogDeviceListDTO;
import cn.skcks.docking.gb28181.sip.manscdp.catalog.CatalogItemDTO;
import cn.skcks.docking.gb28181.sip.manscdp.catalog.CatalogQueryDTO;
import cn.skcks.docking.gb28181.sip.manscdp.catalog.CatalogResponseDTO;
import cn.skcks.docking.gb28181.sip.utils.MANSCDPUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import java.util.Collections;
@Slf4j
public class MANSCDPTest {
public static final String deviceId = "44050100001110000010";
public static final String channelId = "44050100001310000010";
public static final String deviceName = "模拟设备名称";
@Test
public void catalog(){
String sn = String.valueOf(1);
// 创建 目录查询 请求
CatalogQueryDTO catalogQueryDTO = CatalogQueryDTO.builder()
.deviceId("时空旅行者")
.sn(sn)
.build();
log.info("\n{}", MANSCDPUtils.toXml(catalogQueryDTO));
MANSCDPUtils.XMLWrapper<CatalogQueryDTO> query = MANSCDPUtils.XMLWrapper.<CatalogQueryDTO>builder()
.query(catalogQueryDTO)
.build();
String serialize = MANSCDPUtils.toXml(query);
log.info("\n{}", serialize);
MANSCDPUtils.XMLWrapper<CatalogQueryDTO> deserializeCatalogQueryDTO = MANSCDPUtils.parse(serialize, new TypeReference<>(){});
log.info("\n{}",deserializeCatalogQueryDTO);
if (deserializeCatalogQueryDTO == null) {
return;
}
CatalogQueryDTO queryDTO = deserializeCatalogQueryDTO.getQuery();
log.info("{}",queryDTO);
// 创建 目录 查询响应
CatalogItemDTO catalogItemDTO = CatalogItemDTO.builder()
.deviceId(channelId)
.name(deviceName)
.manufacturer("gb28181-docking-platform")
.build();
CatalogResponseDTO catalogResponseDTO = CatalogResponseDTO.builder()
.deviceId(deviceId)
.sn(sn)
.deviceList(new CatalogDeviceListDTO(1,Collections.singletonList(catalogItemDTO)))
.sumNum(0L)
.build();
MANSCDPUtils.XMLWrapper<CatalogResponseDTO> response = MANSCDPUtils.XMLWrapper.<CatalogResponseDTO>builder()
.response(catalogResponseDTO)
.build();
serialize = MANSCDPUtils.toXml(response);
log.info("\n{}", serialize);
MANSCDPUtils.XMLWrapper<CatalogResponseDTO> deserializeCatalogResponseDTO = MANSCDPUtils.parse(serialize, new TypeReference<>(){});
if (deserializeCatalogResponseDTO == null) {
return;
}
CatalogResponseDTO responseDTO = deserializeCatalogResponseDTO.getResponse();
log.info("{}",responseDTO);
}
}