实现群聊和单聊实际差不多,下面给出一个案例供不熟悉的朋友参考。
首先引用smack库(整体pom文件都给出好了)
<?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>
然后用两个用户登录tigase,并进入相同的房间,互发消息可以发现对方能收到
用户1
package com.nufront.xmpp.bootxmppdemo.muc.ssl;
import com.nufront.xmpp.bootxmppdemo.KXMPPAccountManager;
import lombok.extern.slf4j.Slf4j;
import org.jivesoftware.smack.*;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
import org.jivesoftware.smackx.muc.InvitationListener;
import org.jivesoftware.smackx.muc.MultiUserChat;
import org.jivesoftware.smackx.muc.MultiUserChatManager;
import org.jivesoftware.smackx.muc.packet.MUCUser;
import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.EntityJid;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.jid.parts.Resourcepart;
import javax.net.ssl.*;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
/**
* 群聊测试
*/
@Slf4j
public class MucTestA {
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(KXMPPAccountManager.class.getResourceAsStream("/tigase8.keystore"), "nufront@123".toCharArray());
tmf.init(tks);
ctx.init(null, tmf.getTrustManagers(), null);
config = XMPPTCPConnectionConfiguration.builder()
//host可使用外网
.setHost("192.168.43.51")
.setXmppDomain("ubuntu")
.setPort(5222)
.setSslContextFactory(() -> ctx)
.setSecurityMode(ConnectionConfiguration.SecurityMode.required)
.setResource("tcf")
.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
//不验证hostname是否正确
return true;
}
})
//信任自签证书,关键
.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 (Exception e) {
e.printStackTrace();
}
}
@SuppressWarnings("deprecation")
public static void sendMessage(String username, String password, String msg) throws Exception {
//先登录
login(username, password);
//进入房间
MultiUserChatManager mucCM = MultiUserChatManager.getInstanceFor(conn);
EntityBareJid roomJID = JidCreate.entityBareFrom("testroom@muc.ubuntu");
MultiUserChat muc = mucCM.getMultiUserChat(roomJID);
//用户加入房间
muc.join(Resourcepart.from("tsung1"));
muc.sendMessage(msg + username);
//监听服务端的消息
conn.addAsyncStanzaListener(new StanzaListener() {
@Override
public void processStanza(Stanza stanza) throws SmackException.NotConnectedException, InterruptedException, SmackException.NotLoggedInException {
log.info("processStanza:{}", stanza.toXML());
//收到服务端回执则不需要重发消息
}
}, null);
//监听房间的消息
muc.addMessageListener(new MessageListener() {
@Override
public void processMessage(Message message) {
log.info("房间消息:{}", message);
}
});
muc.addParticipantListener(new PresenceListener() {
@Override
public void processPresence(Presence presence) {
log.info("presence消息:{}", presence);
}
});
//邀請监听
mucCM.addInvitationListener(new InvitationListener() {
@Override
public void invitationReceived(XMPPConnection conn, MultiUserChat room, EntityJid inviter, String reason, String password, Message message, MUCUser.Invite invitation) {
log.info("invitationReceived:conn:{},room:{},inviter:{},reason:{},passwd:{},message:{},invitation:{}",
conn, room, inviter, reason, password, message, invitation);
}
});
Thread.sleep(10 * 1000);
log.info("准备离开房间....");
muc.leave();
Thread.sleep(Integer.MAX_VALUE);
}
public static void main(String[] args) throws Exception {
sendMessage("tsung1", "tsung1", "888,this is a test muc message from");
}
}
用户2
package com.nufront.xmpp.bootxmppdemo.muc.ssl;
import com.nufront.xmpp.bootxmppdemo.KXMPPAccountManager;
import lombok.extern.slf4j.Slf4j;
import org.jivesoftware.smack.*;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
import org.jivesoftware.smackx.muc.InvitationListener;
import org.jivesoftware.smackx.muc.MultiUserChat;
import org.jivesoftware.smackx.muc.MultiUserChatManager;
import org.jivesoftware.smackx.muc.packet.MUCUser;
import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.EntityJid;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.jid.parts.Resourcepart;
import javax.net.ssl.*;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
/**
* 群聊测试
*/
@Slf4j
public class MucTestB {
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(KXMPPAccountManager.class.getResourceAsStream("/tigase8.keystore"), "nufront@123".toCharArray());
tmf.init(tks);
ctx.init(null, tmf.getTrustManagers(), null);
config = XMPPTCPConnectionConfiguration.builder()
//host可使用外网
.setHost("192.168.43.51")
.setXmppDomain("ubuntu")
.setPort(5222)
.setSslContextFactory(() -> ctx)
.setSecurityMode(ConnectionConfiguration.SecurityMode.required)
.setResource("tcf")
.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
//不验证hostname是否正确
return true;
}
})
//信任自签证书,关键
.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 (Exception e) {
e.printStackTrace();
}
}
@SuppressWarnings("deprecation")
public static void sendMessage(String username, String password, String msg) throws Exception {
//先登录
login(username, password);
//进入房间
MultiUserChatManager mucCM = MultiUserChatManager.getInstanceFor(conn);
EntityBareJid roomJID = JidCreate.entityBareFrom("testroom@muc.ubuntu");
MultiUserChat muc = mucCM.getMultiUserChat(roomJID);
//用户加入房间
muc.join(Resourcepart.from("tsung2"));
muc.sendMessage(msg + username);
//监听服务端的消息
conn.addAsyncStanzaListener(new StanzaListener() {
@Override
public void processStanza(Stanza stanza) throws SmackException.NotConnectedException, InterruptedException, SmackException.NotLoggedInException {
log.info("processStanza:{}", stanza.toXML());
//收到服务端回执则不需要重发消息
}
}, null);
//监听房间的消息
muc.addMessageListener(new MessageListener() {
@Override
public void processMessage(Message message) {
log.info("房间消息:{}", message);
}
});
muc.addParticipantListener(new PresenceListener() {
@Override
public void processPresence(Presence presence) {
log.info("presence消息:{}", presence);
}
});
//邀請监听
mucCM.addInvitationListener(new InvitationListener() {
@Override
public void invitationReceived(XMPPConnection conn, MultiUserChat room, EntityJid inviter, String reason, String password, Message message, MUCUser.Invite invitation) {
log.info("invitationReceived:conn:{},room:{},inviter:{},reason:{},passwd:{},message:{},invitation:{}",
conn, room, inviter, reason, password, message, invitation);
}
});
/* Thread.sleep(10 * 1000);
log.info("准备离开房间....");
muc.leave();*/
Thread.sleep(Integer.MAX_VALUE);
}
public static void main(String[] args) throws Exception {
sendMessage("tsung2", "tsung2", "123,this is a test muc message from");
}
}
直接运行即可测试群聊进组、发消息、退群功能。