maven引用
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.nufront.xmpp</groupId>
<artifactId>boot-xmpp-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>boot-xmpp-demo</name>
<description>boot-xmpp-demo</description>
<properties>
<java.version>1.8</java.version>
<smack-version>4.4.6</smack-version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.version>3.9.0</maven.compiler.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.igniterealtime.smack</groupId>
<artifactId>smack-core</artifactId>
<version>${smack-version}</version>
</dependency>
<dependency>
<groupId>org.igniterealtime.smack</groupId>
<artifactId>smack-extensions</artifactId>
<version>${smack-version}</version>
</dependency>
<dependency>
<groupId>org.igniterealtime.smack</groupId>
<artifactId>smack-tcp</artifactId>
<version>${smack-version}</version>
</dependency>
<dependency>
<groupId>org.igniterealtime.smack</groupId>
<artifactId>smack-java8</artifactId>
<version>${smack-version}</version>
</dependency>
<dependency>
<groupId>org.igniterealtime</groupId>
<artifactId>rest-api-client</artifactId>
<version>1.1.5</version>
</dependency>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>2.0.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
admin登录后,给kmning发送一条消息,同时监听admin发的消息:
package com.nufront.xmpp.client.conn;
import org.jivesoftware.smack.*;
import org.jivesoftware.smack.chat2.Chat;
import org.jivesoftware.smack.chat2.ChatManager;
import org.jivesoftware.smack.chat2.IncomingChatMessageListener;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.stringprep.XmppStringprepException;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
/**
* @author kangming.ning
* @date 2022-03-08 09:28
* @since 1.0
**/
public class SingleTalkMsgA {
private static XMPPTCPConnectionConfiguration config;
private static AbstractXMPPConnection conn;
static {
try {
SSLContext ctx = SSLContext.getInstance("SSL");
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
KeyStore tks = KeyStore.getInstance("JKS");
tks.load(XMPPSSLTest.class.getResourceAsStream("/tigase8.keystore"), "xxxx".toCharArray());
tmf.init(tks);
ctx.init(null, tmf.getTrustManagers(), null);
config = XMPPTCPConnectionConfiguration.builder()
.setHost("ubuntu")
.setXmppDomain("ubuntu")
.setPort(5222)
.setSslContextFactory(() -> ctx)
.setSecurityMode(ConnectionConfiguration.SecurityMode.required)
.setResource("Smack")
//信任自签证书,关键
.setCustomX509TrustManager(new X509TrustManager() {
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
@Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
@Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
})
.build();
conn = new XMPPTCPConnection(config);
conn.connect();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void login(String username, String password) {
try {
if (conn != null) {
conn.login(username, password);
System.out.println("user " + username + " login successfully.");
}
} catch (XMPPException e) {
e.printStackTrace();
} catch (SmackException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@SuppressWarnings("deprecation")
public static void sendMessage(String username, String password, String msg) {
//先登录
login(username, password);
//监听服务端的消息
conn.addAsyncStanzaListener(new StanzaListener() {
@Override
public void processStanza(Stanza stanza) throws SmackException.NotConnectedException, InterruptedException, SmackException.NotLoggedInException {
System.out.println("processStanza:"+stanza.toXML());
}
},null);
//构建聊天室
final ChatManager cm = ChatManager.getInstanceFor(conn);
cm.addIncomingListener(new IncomingChatMessageListener() {
@Override
public void newIncomingMessage(EntityBareJid from, Message message, Chat chat) {
System.out.println("message from : " + from + " : " + message.getBody());
}
});
try {
//admin登录后,给kmning发送一条消息
EntityBareJid jid = JidCreate.entityBareFrom("kmning@ubuntu");
Chat chat = cm.chatWith(jid);
Message message = new Message();
message.setBody(msg);
message.setType(Message.Type.chat);
chat.send(message);
Thread.sleep(Integer.MAX_VALUE);
} catch (XmppStringprepException e) {
e.printStackTrace();
} catch (SmackException.NotConnectedException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
sendMessage("admin", "123456", "hi, kmning,6666");
}
}
kmning登录,给admin发一条消息并接收来自admin的消息
package com.nufront.xmpp.client.conn;
import org.jivesoftware.smack.*;
import org.jivesoftware.smack.chat2.Chat;
import org.jivesoftware.smack.chat2.ChatManager;
import org.jivesoftware.smack.chat2.IncomingChatMessageListener;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.stringprep.XmppStringprepException;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
/**
* @author kangming.ning
* @date 2022-03-08 09:28
* @since 1.0
**/
public class SingleTalkMsgB {
private static XMPPTCPConnectionConfiguration config;
private static AbstractXMPPConnection conn;
static {
try {
SSLContext ctx = SSLContext.getInstance("SSL");
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
KeyStore tks = KeyStore.getInstance("JKS");
tks.load(XMPPSSLTest.class.getResourceAsStream("/tigase8.keystore"), "xxx".toCharArray());
tmf.init(tks);
ctx.init(null, tmf.getTrustManagers(), null);
config = XMPPTCPConnectionConfiguration.builder()
.setHost("ubuntu")
.setXmppDomain("ubuntu")
.setPort(5222)
.setSslContextFactory(() -> ctx)
.setSecurityMode(ConnectionConfiguration.SecurityMode.required)
.setResource("Smack")
//信任自签证书,关键
.setCustomX509TrustManager(new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
@Override
public void checkClientTrusted(
X509Certificate[] certs, String authType) {
}
@Override
public void checkServerTrusted(
X509Certificate[] certs, String authType) {
}
})
.build();
conn = new XMPPTCPConnection(config);
conn.connect();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void login(String username, String password) {
try {
if (conn != null) {
conn.login(username, password);
System.out.println("user " + username + " login successfully.");
}
} catch (XMPPException e) {
e.printStackTrace();
} catch (SmackException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@SuppressWarnings("deprecation")
public static void sendMessage(String username, String password, String msg) {
//先登录
login(username, password);
//监听服务端的消息
conn.addAsyncStanzaListener(new StanzaListener() {
@Override
public void processStanza(Stanza stanza) throws SmackException.NotConnectedException, InterruptedException, SmackException.NotLoggedInException {
System.out.println("processStanza:"+stanza.toXML());
}
},null);
//构建聊天室
final ChatManager cm = ChatManager.getInstanceFor(conn);
cm.addIncomingListener(new IncomingChatMessageListener() {
@Override
public void newIncomingMessage(EntityBareJid from, Message message, Chat chat) {
System.out.println("message from : " + from + " : " + message.getBody());
}
});
try {
//kmning登录后,给admin发送一条消息
EntityBareJid jid = JidCreate.entityBareFrom("admin@ubuntu");
Chat chat = cm.chatWith(jid);
Message message = new Message();
message.setBody(msg);
message.setType(Message.Type.chat);
chat.send(message);
Thread.sleep(Integer.MAX_VALUE);
} catch (XmppStringprepException e) {
e.printStackTrace();
} catch (SmackException.NotConnectedException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
sendMessage("kmning", "123456", "hi, admin,6666");
}
}
依次执行这两份代码则可以看到,admin和kmning都能收到来自对方的消息。当然,后登录的一个收到的可能是离线消息,因为当消息发出去,对方不在线时,tigase会将消息放到离线消息表里面,对方上线后再将消息发出去。