我对XMPP和Spring Integration完全陌生,想向FCM用户发送消息。我为出站消息创建了XML配置,如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-xmpp="http://www.springframework.org/schema/integration/xmpp"
...>
<context:component-scan base-package="com.avantovr.esysync_backend.webservices.restful.fcm.xmppserver" />
<int-xmpp:outbound-channel-adapter id="xmppOutboundAdapter" channel="xmppOutboundChannel" xmpp-connection="xmppConnection"/>
<int:service-activator ref="fcmSender" input-channel="xmppOutbound" />
<int:logging-channel-adapter id="xmppOutboundChannel" log-full-message="true" />
</beans>
现在,我想创建一个Java类,其中有一种方法可以通过XMPP将Downstrwam messagr发送到FCM。请问有任何初学者通过Spring集成向FCM发送和接收xmpp消息的示例吗?
这可能不是最佳解决方案,但对我来说足够好。第一次处理XMPP。
我没有除pom.xml依赖项之外的任何XML配置。
睡眠5秒钟,断开连接后重新连接。 FCM有时会断开XMPP连接以达到负载平衡。
发送回ACK有效,未测试接收ACK和NACK。
要从Java发送消息-> fcm->电话;
@Autowired
private XmppConfig xmppConfig;
xmppConfig.getXmppConnection().sendStanza(generateStanza(messageId,json));
上面的json应该像这样,来自https://firebase.google.com/docs/cloud-messaging/server
{
"to":"REGISTRATION_ID", // "to" replaces "registration_ids"
"message_id":"m-1366082849205" // new required field
"data":
{
"hello":"world",
}
"time_to_live":"600",
"delivery_receipt_requested": true/false
}
smack依赖项>>
<dependency> <groupId>org.igniterealtime.smack</groupId> <artifactId>smack-tcp</artifactId> <version>4.3.4</version> </dependency> <dependency> <groupId>org.igniterealtime.smack</groupId> <artifactId>smack-java7</artifactId> <version>4.3.4</version> </dependency> <dependency> <groupId>org.igniterealtime.smack</groupId> <artifactId>smack-extensions</artifactId> <version>4.3.4</version> </dependency> <dependency> <groupId>org.json</groupId> <artifactId>json</artifactId> <version>20190722</version> </dependency>
application.properties
[email protected] fcm.server_key=YOUR_SERVER_KEY fcm.host=fcm-xmpp.googleapis.com fcm.port=5235
XmppConfig.java
import com.alessoft.utils.Utils; import org.jivesoftware.smack.ConnectionConfiguration; import org.jivesoftware.smack.ConnectionListener; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.roster.Roster; import org.jivesoftware.smack.tcp.XMPPTCPConnection; import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration; import org.jxmpp.stringprep.XmppStringprepException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import javax.annotation.PostConstruct; import javax.net.ssl.SSLSocketFactory; @Configuration class XmppConfig implements ConnectionListener { @Value("${fcm.sender_id}") private String senderId; @Value("${fcm.server_key}") private String server_key; @Value("${fcm.host}") private String host; @Value("${fcm.port}") private int port; @Autowired private XmppService xmppService; private Logger logger = LoggerFactory.getLogger(XmppConfig.class); private volatile boolean xmppConnected; private XMPPTCPConnection xmppConnection; public XMPPTCPConnection getXmppConnection() { return xmppConnection; } @PostConstruct public void postConstruct() throws Exception { new Thread(() -> prepareXmppConnection()).start(); } public XMPPConnection prepareXmppConnection() { XMPPTCPConnectionConfiguration conf = null; try { conf = XMPPTCPConnectionConfiguration.builder() .setHost(host) .setPort(port) .setSendPresence(false) .setSecurityMode(ConnectionConfiguration.SecurityMode.disabled) .setSocketFactory(SSLSocketFactory.getDefault()) .setUsernameAndPassword(senderId, server_key) .setXmppDomain("somedomain.com") .build(); } catch (XmppStringprepException e) { logger.info("prepareXmppConnection error", e); } xmppConnection = new XMPPTCPConnection(conf); xmppConnection.addAsyncStanzaListener(xmppService, xmppService); xmppConnection.addConnectionListener(this); Roster.getInstanceFor(xmppConnection).setRosterLoadedAtLogin(false); establishXmppConnection(); return xmppConnection; } private void establishXmppConnection() { try { xmppConnection.connect(); xmppConnection.login(); } catch (Exception e) { logger.info("XMPP establishXmppConnection error", e); } } @Override public void connectionClosedOnError(Exception e) { logger.info("LOST CONNECTION TO FCM XMPP ON ERROR", e); Utils.sleep(5000); establishXmppConnection(); } @Override public void connectionClosed() { logger.info("LOST CONNECTION TO FCM XMPP"); Utils.sleep(5000); establishXmppConnection(); } @Override public void connected(XMPPConnection connection) { logger.info("CONNECTED TO FCM XMPP"); } @Override public void authenticated(XMPPConnection connection, boolean resumed) { logger.info("AUTHENTICATED TO FCM XMPP"); } }
XmppService.java
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.StanzaListener;
import org.jivesoftware.smack.filter.StanzaFilter;
import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.json.JSONObject;
import org.json.XML;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class XmppService implements StanzaListener, StanzaFilter {
private Logger logger = LoggerFactory.getLogger(XmppService.class);
@Autowired
private XmppConfig xmppConfig;
@Override
public void processStanza(Stanza stanzaXml) throws SmackException.NotConnectedException, InterruptedException, SmackException.NotLoggedInException {
JSONObject stanza = XML.toJSONObject(stanzaXml.toXML(null).toString());
if (!stanza.has("message")) return;
JSONObject message = stanza.getJSONObject("message");
if (message.has("type")) {
normalMessage(message);
} else {
otherMessage(message);
}
}
private void otherMessage(JSONObject message) {
JSONObject gcm = message.getJSONObject("gcm");
String contentString = gcm.getString("content");
JSONObject content = new JSONObject(contentString);
if (content.getString("message_type").equals("ack")) {
logger.info("RECEIVED ACK");
} else if (content.getString("message_type").equals("nack")) {
logger.info("RECEIVED NACK: \n" + content.toString(2));
} else {
logger.info("RECEIVED UNKNOWN: \n" + content.toString());
}
}
private void normalMessage(JSONObject message) {
JSONObject gcm = message.getJSONObject("gcm");
String contentString = gcm.getString("content");
JSONObject content = new JSONObject(contentString);
String message_id = content.getString("message_id");
String from = content.getString("from");
if (content.has("message_type")) {
logger.info("NOT FROM DEVICE:\n" + message.toString());
} else {
processMessage(content);
sendAck(message_id, from);
}
}
private void processMessage(JSONObject content) {
// your own processing
}
private void sendAck(String message_id, String regId) {
try {
JSONObject json = new JSONObject();
json.put("to", regId);
json.put("message_id", message_id);
json.put("message_type", "ack");
String messageString = String.format("<message><gcm xmlns=\"google:mobile:data\">%s</gcm></message>", json.toString());
Stanza stanza = PacketParserUtils.parseStanza(messageString);
xmppConfig.getXmppConnection().sendStanza(stanza);
} catch (Exception e) {
logger.info("fcm sending ack error", e);
}
}
private Stanza generateStanza(String messageId, JSONObject json) {
String messageString = String.format("<message id=\"%s\"><gcm xmlns=\"google:mobile:data\">%s</gcm></message>", messageId, json.toString());
try {
return PacketParserUtils.parseStanza(messageString);
} catch (Exception e) {
logger.info("generateStanza error", e);
return null;
}
}
@Override
public boolean accept(Stanza stanza) {
return true;
}
}