diff --git a/common/pom.xml b/common/pom.xml
index cb1d127..6e2abfb 100644
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -44,6 +44,10 @@
com.fasterxml.jackson.core
jackson-databind
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-xml
+
com.fasterxml.jackson.core
jackson-annotations
diff --git a/common/src/main/java/cn/skcks/docking/gb28181/common/json/JsonUtils.java b/common/src/main/java/cn/skcks/docking/gb28181/common/json/JsonUtils.java
index 3859a77..ff5e9f2 100644
--- a/common/src/main/java/cn/skcks/docking/gb28181/common/json/JsonUtils.java
+++ b/common/src/main/java/cn/skcks/docking/gb28181/common/json/JsonUtils.java
@@ -48,9 +48,9 @@ public class JsonUtils {
}
}
- public static T parse(String json, TypeReference clazz) {
+ public static T parse(String xml, TypeReference clazz) {
try {
- return mapper.readValue(json, clazz);
+ return mapper.readValue(xml, clazz);
} catch (Exception e) {
e.printStackTrace();
return null;
diff --git a/common/src/main/java/cn/skcks/docking/gb28181/common/xml/XmlUtils.java b/common/src/main/java/cn/skcks/docking/gb28181/common/xml/XmlUtils.java
new file mode 100644
index 0000000..addd0b3
--- /dev/null
+++ b/common/src/main/java/cn/skcks/docking/gb28181/common/xml/XmlUtils.java
@@ -0,0 +1,111 @@
+package cn.skcks.docking.gb28181.common.xml;
+
+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.ObjectMapper;
+import com.fasterxml.jackson.databind.PropertyNamingStrategies;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.dataformat.xml.XmlMapper;
+
+import java.nio.charset.Charset;
+
+@SuppressWarnings({"unused"})
+public class XmlUtils {
+ private static final ObjectMapper 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());
+ }
+
+ public static String toXml(Object obj) {
+ try {
+ return mapper.writeValueAsString(obj);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public static byte[] toByteXml(Object obj) {
+ try {
+ return mapper.writeValueAsString(obj).getBytes();
+ } 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) {
+ try {
+ return mapper.writeValueAsString(obj).getBytes(Charset.forName(charset));
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public static T parse(byte[] xml, Class clazz) {
+ return parse(new String(xml), clazz);
+ }
+
+ public static T parse(byte[] xml, Class clazz, Charset charset) {
+ return parse(new String(xml, charset), clazz);
+ }
+
+ public static T parse(byte[] xml, Class clazz, String charset) {
+ return parse(new String(xml, Charset.forName(charset)), clazz);
+ }
+
+ public static T parse(String xml, Class clazz) {
+ try {
+ return mapper.readValue(xml, clazz);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public static T parse(byte[] xml, TypeReference clazz) {
+ return parse(new String(xml), clazz);
+ }
+
+ public static T parse(byte[] xml, TypeReference clazz, Charset charset) {
+ return parse(new String(xml, charset), clazz);
+ }
+
+ public static T parse(byte[] xml, TypeReference clazz, String charset) {
+ return parse(new String(xml, Charset.forName(charset)), clazz);
+ }
+
+ public static T parse(String xml, TypeReference clazz) {
+ try {
+ return mapper.readValue(xml, clazz);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public static T convert(Object object, Class clazz) {
+ return XmlUtils.parse(XmlUtils.toXml(object), clazz);
+ }
+}
diff --git a/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/gb28181/constant/CmdType.java b/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/gb28181/constant/CmdType.java
new file mode 100644
index 0000000..68e09ea
--- /dev/null
+++ b/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/gb28181/constant/CmdType.java
@@ -0,0 +1,17 @@
+package cn.skcks.docking.gb28181.core.sip.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 RECORD_INFO = "RecordInfo";
+ public static final String MEDIA_STATUS = "MediaStatus";
+ public static final String CONFIG_DOWNLOAD = "ConfigDownload";
+ public static final String PRESET_QUERY = "PresetQuery";
+}
diff --git a/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/gb28181/constant/DefaultConstant.java b/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/gb28181/constant/GB28181Constant.java
similarity index 84%
rename from gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/gb28181/constant/DefaultConstant.java
rename to gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/gb28181/constant/GB28181Constant.java
index 5c29765..6c20d75 100644
--- a/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/gb28181/constant/DefaultConstant.java
+++ b/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/gb28181/constant/GB28181Constant.java
@@ -1,6 +1,6 @@
package cn.skcks.docking.gb28181.core.sip.gb28181.constant;
-public class DefaultConstant {
+public class GB28181Constant {
public static final String CHARSET = "GB2312";
public static final String GEO_COORD_SYS = "WGS84";
}
diff --git a/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/message/processor/MessageProcessor.java b/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/message/processor/MessageProcessor.java
index 09df865..181986b 100644
--- a/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/message/processor/MessageProcessor.java
+++ b/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/message/processor/MessageProcessor.java
@@ -1,6 +1,5 @@
package cn.skcks.docking.gb28181.core.sip.message.processor;
-import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -15,8 +14,10 @@ public interface MessageProcessor {
class Method {
public static final String REGISTER = "REGISTER";
+ public static final String MESSAGE = "MESSAGE";
}
+ void init();
void process(RequestEvent requestEvent);
default MessageFactory getMessageFactory() {
diff --git a/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/message/processor/message/request/MessageRequestProcessor.java b/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/message/processor/message/request/MessageRequestProcessor.java
new file mode 100644
index 0000000..a4d3615
--- /dev/null
+++ b/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/message/processor/message/request/MessageRequestProcessor.java
@@ -0,0 +1,77 @@
+package cn.skcks.docking.gb28181.core.sip.message.processor.message.request;
+
+import cn.skcks.docking.gb28181.common.xml.XmlUtils;
+import cn.skcks.docking.gb28181.core.sip.gb28181.constant.CmdType;
+import cn.skcks.docking.gb28181.core.sip.message.processor.message.request.dto.MessageDto;
+import cn.skcks.docking.gb28181.core.sip.gb28181.constant.GB28181Constant;
+import cn.skcks.docking.gb28181.core.sip.listener.SipListener;
+import cn.skcks.docking.gb28181.core.sip.message.processor.MessageProcessor;
+import cn.skcks.docking.gb28181.core.sip.message.sender.SipMessageSender;
+import cn.skcks.docking.gb28181.core.sip.utils.SipUtil;
+import cn.skcks.docking.gb28181.orm.mybatis.dynamic.model.DockingDevice;
+import cn.skcks.docking.gb28181.service.docking.device.DockingDeviceService;
+import gov.nist.javax.sip.message.SIPRequest;
+import gov.nist.javax.sip.message.SIPResponse;
+import jakarta.annotation.PostConstruct;
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import javax.sip.RequestEvent;
+import javax.sip.header.CallIdHeader;
+import javax.sip.message.Response;
+
+@Slf4j
+@RequiredArgsConstructor
+@Component
+public class MessageRequestProcessor implements MessageProcessor {
+ private final SipListener sipListener;
+ private final DockingDeviceService deviceService;
+ private final SipMessageSender sender;
+
+ @PostConstruct
+ @Override
+ public void init() {
+ sipListener.addProcessor(Method.MESSAGE, this);
+ }
+
+ @Override
+ public void process(RequestEvent requestEvent) {
+ SIPRequest request = (SIPRequest)requestEvent.getRequest();
+ String deviceId = SipUtil.getUserIdFromFromHeader(request);
+ CallIdHeader callIdHeader = request.getCallIdHeader();
+
+ MessageDto messageDto = XmlUtils.parse(request.getRawContent(), MessageDto.class, GB28181Constant.CHARSET);
+ log.debug("接收到的消息 => {}", messageDto);
+
+ DockingDevice device = deviceService.getDevice(deviceId);
+ String senderIp = request.getLocalAddress().getHostAddress();
+
+ if(device == null){
+ log.info("未找到相关设备信息 => {}", deviceId);
+ Response response = response(request,Response.NOT_FOUND,"设备未注册");
+ sender.send(senderIp,response);
+ return;
+ }
+
+ if(messageDto.getCmdType().equalsIgnoreCase(CmdType.KEEPALIVE)){
+ Response response = response(request,Response.OK,"OK");
+ // 更新设备在线状态
+ deviceService.online(device, response);
+ sender.send(senderIp,response);
+ }
+ }
+
+ @SneakyThrows
+ public Response response(SIPRequest request, int status, String message){
+ if (request.getToHeader().getTag() == null) {
+ request.getToHeader().setTag(SipUtil.generateTag());
+ }
+ SIPResponse response = (SIPResponse)getMessageFactory().createResponse(status, request);
+ if (message != null) {
+ response.setReasonPhrase(message);
+ }
+ return response;
+ }
+}
diff --git a/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/message/processor/message/request/dto/MessageDto.java b/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/message/processor/message/request/dto/MessageDto.java
new file mode 100644
index 0000000..a69725a
--- /dev/null
+++ b/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/message/processor/message/request/dto/MessageDto.java
@@ -0,0 +1,19 @@
+package cn.skcks.docking.gb28181.core.sip.message.processor.message.request.dto;
+
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
+import lombok.Data;
+
+@JacksonXmlRootElement(localName = "xml")
+@Data
+public class MessageDto {
+ private String cmdType;
+
+ @JacksonXmlProperty(localName = "SN")
+ private String sn;
+
+ @JacksonXmlProperty(localName = "DeviceID")
+ private String deviceId;
+
+ private String status;
+}
diff --git a/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/message/processor/register/request/RegisterRequestProcessor.java b/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/message/processor/register/request/RegisterRequestProcessor.java
index c81ba34..f6b0b18 100644
--- a/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/message/processor/register/request/RegisterRequestProcessor.java
+++ b/gb28181-service/src/main/java/cn/skcks/docking/gb28181/core/sip/message/processor/register/request/RegisterRequestProcessor.java
@@ -4,7 +4,7 @@ import cn.hutool.core.date.DateUtil;
import cn.skcks.docking.gb28181.config.sip.SipConfig;
import cn.skcks.docking.gb28181.core.sip.dto.RemoteInfo;
import cn.skcks.docking.gb28181.core.sip.dto.SipTransactionInfo;
-import cn.skcks.docking.gb28181.core.sip.gb28181.constant.DefaultConstant;
+import cn.skcks.docking.gb28181.core.sip.gb28181.constant.GB28181Constant;
import cn.skcks.docking.gb28181.core.sip.gb28181.sip.GbSipDate;
import cn.skcks.docking.gb28181.core.sip.listener.SipListener;
import cn.skcks.docking.gb28181.core.sip.message.auth.DigestServerAuthenticationHelper;
@@ -46,7 +46,8 @@ public class RegisterRequestProcessor implements MessageProcessor {
private final DockingDeviceService dockingDeviceService;
@PostConstruct
- private void init(){
+ @Override
+ public void init(){
sipListener.addProcessor(Method.REGISTER,this);
}
@@ -61,7 +62,7 @@ public class RegisterRequestProcessor implements MessageProcessor {
SipUri uri = (SipUri)address.getURI();
String deviceId = uri.getUser();
log.debug("请求注册 设备id => {}", deviceId);
- DockingDevice device = dockingDeviceService.getDeviceInfo(deviceId);
+ DockingDevice device = dockingDeviceService.getDevice(deviceId);
String senderIp = request.getLocalAddress().getHostAddress();
RemoteInfo remoteInfo = SipUtil.getRemoteInfoFromRequest(request, false);
log.debug("远程连接信息 => {}", remoteInfo);
@@ -135,8 +136,8 @@ public class RegisterRequestProcessor implements MessageProcessor {
if (device == null) {
device = new DockingDevice();
device.setStreamMode(ListeningPoint.UDP);
- device.setCharset(DefaultConstant.CHARSET);
- device.setGeoCoordSys(DefaultConstant.GEO_COORD_SYS);
+ device.setCharset(GB28181Constant.CHARSET);
+ device.setGeoCoordSys(GB28181Constant.GEO_COORD_SYS);
device.setDeviceId(deviceId);
device.setOnLine(false);
} else {
@@ -144,10 +145,10 @@ public class RegisterRequestProcessor implements MessageProcessor {
device.setStreamMode(ListeningPoint.UDP);
}
if (ObjectUtils.isEmpty(device.getCharset())) {
- device.setCharset(DefaultConstant.CHARSET);
+ device.setCharset(GB28181Constant.CHARSET);
}
if (ObjectUtils.isEmpty(device.getGeoCoordSys())) {
- device.setGeoCoordSys(DefaultConstant.GEO_COORD_SYS);
+ device.setGeoCoordSys(GB28181Constant.GEO_COORD_SYS);
}
}
diff --git a/gb28181-service/src/main/java/cn/skcks/docking/gb28181/service/docking/device/DockingDeviceService.java b/gb28181-service/src/main/java/cn/skcks/docking/gb28181/service/docking/device/DockingDeviceService.java
index 79480f9..1c1adaf 100644
--- a/gb28181-service/src/main/java/cn/skcks/docking/gb28181/service/docking/device/DockingDeviceService.java
+++ b/gb28181-service/src/main/java/cn/skcks/docking/gb28181/service/docking/device/DockingDeviceService.java
@@ -16,7 +16,6 @@ import org.mybatis.dynamic.sql.SqlBuilder;
import org.springframework.stereotype.Service;
import javax.sip.message.Response;
-import java.util.concurrent.TimeUnit;
@Slf4j
@Service
@@ -32,7 +31,7 @@ public class DockingDeviceService {
* @param deviceId 设备id
* @return 设备信息
*/
- public DockingDevice getDeviceInfo(String deviceId) {
+ public DockingDevice getDevice(String deviceId) {
DockingDevice device = deviceCacheService.getDevice(deviceId);
if (device == null) {
device = dockingDeviceMapper
@@ -65,7 +64,7 @@ public class DockingDeviceService {
dockingDeviceMapper.insert(device);
});
- getDeviceInfo(deviceId);
+ getDevice(deviceId);
onlineCacheService.setOnline(deviceId, DeviceConstant.KEEP_ALIVE_INTERVAL * 3, DeviceConstant.UNIT);
setTransaction(deviceId, response);
}