快速浏览了RFC3920,XEP-0147和RFC3921,大致明白了XMPP的数据格式和通讯原理,接着开始尝试基于Vysper(我用的版本是0.7)做点小定制,尤其是增加“联系人”相关的数据。
先从改造demo开始吧,把org.apache.vysper.xmpp.authorization.SimpleUserAuthorization、org.apache.vysper.xmpp.modules.roster.persistence.MemoryRosterManager和org.apache.vysper.storage.inmemory.MemoryStorageProviderRegistry的源码拿到手,根据自己的喜好做修改:
1、AccountManagementImpl:帐户管理相关的代码实现
package z.vysper.impl; import org.apache.log4j.Logger; import org.apache.vysper.xmpp.addressing.Entity; import org.apache.vysper.xmpp.addressing.EntityImpl; import org.apache.vysper.xmpp.authorization.AccountCreationException; import org.apache.vysper.xmpp.authorization.AccountManagement; import org.apache.vysper.xmpp.authorization.UserAuthorization; import z.vysper.test.TestData; /** * @author auzll * @blog http://auzll.iteye.com */ public class AccountManagementImpl implements AccountManagement, UserAuthorization { private static final Logger LOG = Logger.getLogger(AccountManagementImpl.class); private static final boolean INFO = LOG.isInfoEnabled(); public void addUser(Entity username, String password) throws AccountCreationException{ if (INFO) { LOG.info("method:addUser,username:" + username + ",passwordExist:" + (null != password)); } throw new AccountCreationException("无法添加用户"); } public void changePassword(Entity username, String password) throws AccountCreationException { if (INFO) { LOG.info("method:changePassword,username:" + username + ",passwordExist:" + (null != password)); } throw new AccountCreationException("无法修改用户密码"); } public boolean verifyCredentials(Entity jid, String passwordCleartext, Object credentials) { if (INFO) { LOG.info("method:verifyCredentials,jid:" + jid + ",passwordExist:" + (null != passwordCleartext) + ",credentials:" + (null != credentials ? credentials.getClass().getSimpleName() : null)); } return verify(jid.getBareJID(), passwordCleartext); } public boolean verifyCredentials(String username, String passwordCleartext, Object credentials) { if (INFO) { LOG.info("method:verifyCredentials,username:" + username + ",passwordExist:" + (null != passwordCleartext) + ",credentials:" + (null != credentials ? credentials.getClass().getSimpleName() : null)); } return verify(EntityImpl.parseUnchecked(username).getBareJID(), passwordCleartext); } public boolean verifyAccountExists(Entity jid) { if (INFO) { LOG.info("method:verifyAccountExists,jid:" + jid); } return TestData.USER_NAME_PASSWORD.get(jid.getBareJID()) != null; } private boolean verify(Entity username, String passwordCleartext) { return passwordCleartext.equals(TestData.USER_NAME_PASSWORD.get(username)); } }
2、RosterManagerImpl:通讯录相关的代码实现
package z.vysper.impl; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.apache.log4j.Logger; import org.apache.vysper.xmpp.addressing.Entity; import org.apache.vysper.xmpp.modules.ServerRuntimeContextService; import org.apache.vysper.xmpp.modules.roster.MutableRoster; import org.apache.vysper.xmpp.modules.roster.Roster; import org.apache.vysper.xmpp.modules.roster.RosterException; import org.apache.vysper.xmpp.modules.roster.RosterItem; import org.apache.vysper.xmpp.modules.roster.persistence.RosterManager; import z.vysper.test.TestData; /** * @author auzll * @blog http://auzll.iteye.com */ public class RosterManagerImpl implements RosterManager, ServerRuntimeContextService { private static final Logger LOG = Logger.getLogger(RosterManagerImpl.class); private static final boolean INFO = LOG.isInfoEnabled(); // private static final boolean DEBUG = LOG.isDebugEnabled(); // TODO private Map<Entity, Roster> rosterMap = new HashMap<Entity, Roster>(); protected Roster addNewRosterInternal(Entity jid) { if (INFO) { LOG.info("method:addNewRosterInternal,jid:" + jid); } MutableRoster mutableRoster = new MutableRoster(); rosterMap.put(jid.getBareJID(), (MutableRoster) mutableRoster); return mutableRoster; } protected Roster retrieveRosterInternal(Entity bareJid) { if (INFO) { LOG.info("method:retrieveRosterInternal,bareJid:" + bareJid); } if (!rosterMap.containsKey(bareJid)) { // TODO MutableRoster roster = new MutableRoster(); if (bareJid.getDomain().equals(TestData.SERVER_DOMAIN)) { Iterator<RosterItem> it = TestData.SHARE_ROSTER.iterator(); while (it.hasNext()) { RosterItem item = it.next(); if (!item.getJid().equals(bareJid)) { // 剔除当前账户 roster.addItem(item); } } } rosterMap.put(bareJid, roster); } return rosterMap.get(bareJid); } public Roster retrieve(Entity jid) { jid = jid.getBareJID(); return retrieveRosterInternal(jid); } public void addContact(Entity jid, RosterItem rosterItem) throws RosterException { throw new RosterException("无法添加联系人"); } public RosterItem getContact(Entity jidUser, Entity jidContact) throws RosterException { if (jidUser == null) throw new RosterException("jid not provided"); Roster roster = retrieve(jidUser); if (roster == null) throw new RosterException("roster not available for jid = " + jidUser.getFullQualifiedName()); return roster.getEntry(jidContact); } public void removeContact(Entity jidUser, Entity jidContact) throws RosterException { throw new RosterException("无法删除联系人"); } public String getServiceName() { return RosterManager.SERVER_SERVICE_ROSTERMANAGER; } }
3、StorageProviderRegistryImpl:用于辅助注册上面两个实现类的
package z.vysper.impl; import org.apache.vysper.storage.OpenStorageProviderRegistry; /** * @author auzll * @blog http://auzll.iteye.com */ public class StorageProviderRegistryImpl extends OpenStorageProviderRegistry { public StorageProviderRegistryImpl() { add(new AccountManagementImpl()); add(new RosterManagerImpl()); // provider from external modules, low coupling, fail when modules are not present add("org.apache.vysper.xmpp.modules.extension.xep0060_pubsub.storageprovider.LeafNodeInMemoryStorageProvider"); add("org.apache.vysper.xmpp.modules.extension.xep0060_pubsub.storageprovider.CollectionNodeInMemoryStorageProvider"); //add("org.apache.vysper.xmpp.modules.extension.xep0160_offline_storage.MemoryOfflineStorageProvider"); } }
4、TestData:自己设定的一些测试数据
/** * */ package z.vysper.test; import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.apache.vysper.xmpp.addressing.Entity; import org.apache.vysper.xmpp.addressing.EntityImpl; import org.apache.vysper.xmpp.modules.roster.AskSubscriptionType; import org.apache.vysper.xmpp.modules.roster.MutableRoster; import org.apache.vysper.xmpp.modules.roster.Roster; import org.apache.vysper.xmpp.modules.roster.RosterItem; import org.apache.vysper.xmpp.modules.roster.SubscriptionType; /** * 测试数据 * @author auzll * @blog http://auzll.iteye.com */ public final class TestData { public static final Map<Entity, String> USER_NAME_PASSWORD; public static final Roster SHARE_ROSTER; public static final String SERVER_DOMAIN = "helloworld.com"; static { try { // 添加测试数据 Map<Entity, String> map = new HashMap<Entity, String>(); MutableRoster roster = new MutableRoster(); String password = "testing"; String entityFormat = "contact%d@%s"; int total = 10; for (int i = 1; i <= total; i++) { Entity entity = EntityImpl.parse(String.format(entityFormat, i, SERVER_DOMAIN)); map.put(entity, password); roster.addItem(new RosterItem(entity, "姓名" + i, SubscriptionType.BOTH, AskSubscriptionType.NOT_SET)); } USER_NAME_PASSWORD = Collections.unmodifiableMap(map); SHARE_ROSTER = roster; } catch (Exception e) { throw new ExceptionInInitializerError(e.getMessage()); } } }
5、spring配置文件:好久没用spring了,不过用起来还是蛮简单的,只是没深入看过spring的源码。(在此推荐另一款容器,就是google出品的guice啦,我经常用的,非常精简,代码也很有学习价值)
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd"> <beans> <!-- 使用自己配置的Registry --> <bean id="zStorageRegistry" class="z.vysper.impl.StorageProviderRegistryImpl" /> <!-- choose one of the storage registries --> <alias name="zStorageRegistry" alias="storageRegistry" /> <bean id="tcpEndpoint" class="org.apache.vysper.mina.TCPEndpoint"> </bean> <bean id="server" class="org.apache.vysper.spring.SpringCompatibleXMPPServer" init-method="init" destroy-method="destroy"> <!-- TODO change domain name to your domain --> <constructor-arg value="helloworld.com"/> <property name="endpoints"> <list> <ref bean="tcpEndpoint"/> <!--<ref bean="boshEndpoint"/>--> </list> </property> <property name="storageProviderRegistry" ref="storageRegistry" /> <property name="certificateFile" value="classpath:bogus_mina_tls.cert" /> <property name="certificatePassword" value="boguspw" /> <property name="modules" > <list> <bean class="org.apache.vysper.xmpp.modules.extension.xep0092_software_version.SoftwareVersionModule"/> <bean class="org.apache.vysper.xmpp.modules.extension.xep0202_entity_time.EntityTimeModule" /> <bean class="org.apache.vysper.xmpp.modules.extension.xep0054_vcardtemp.VcardTempModule" /> <bean class="org.apache.vysper.xmpp.modules.extension.xep0119_xmppping.XmppPingModule" /> <bean class="org.apache.vysper.xmpp.modules.extension.xep0049_privatedata.PrivateDataModule" /> <bean class="org.apache.vysper.xmpp.modules.extension.xep0050_adhoc_commands.AdhocCommandsModule" /> <bean class="org.apache.vysper.xmpp.modules.extension.xep0133_service_administration.ServiceAdministrationModule" > <property name="addAdmins"> <list><value>admin@helloworld.com</value></list> </property> </bean> <!-- below some more modules which are available as separately-built jars. make sure they are on the classpath when enabling them or remove the beans below, depending on the features your server should expose --> <!--<bean class="org.apache.vysper.xmpp.modules.extension.xep0060_pubsub.PublishSubscribeModule" />--> <bean class="org.apache.vysper.xmpp.modules.extension.xep0045_muc.MUCModule" /> </list> </property> </bean> </beans>
6、改好代码和配置文件之后,程序就可以跑起来咯,截两个包含联系人的客户端界面:
好了,至此已完成帐户验证逻辑和通讯录相关逻辑的整合,下一步再找找企业邮箱的通讯录整合一下就可以正式完成我这个小项目的demo了!!
距离这款“基于企业邮箱通讯录打造的XMPP聊天系统”的诞生又进一步了!感兴趣的朋友可以关注 qiyeliao.com 哦!
相关推荐
小程序源码 云笔记 (代码+截图)小程序源码 云笔记 (代码+截图)小程序源码 云笔记 (代码+截图)小程序源码 云笔记 (代码+截图)小程序源码 云笔记 (代码+截图)小程序源码 云笔记 (代码+截图)小程序源码 云笔记 (代码+...
nginx项目源码学习及笔记.zip
狂神SpringBoot笔记+源码 狂神SpringBoot笔记+源码 狂神SpringBoot笔记+源码 狂神SpringBoot笔记+源码 狂神SpringBoot笔记+源码 狂神SpringBoot笔记+源码 狂神SpringBoot笔记+源码 狂神SpringBoot笔记+源码 狂神...
【资源说明】 1、该资源包括项目的全部源码,下载可以直接使用! 2、本项目适合作为计算机、数学、电子信息等专业的课程设计、期末大作业和毕设项目,作为...基于Django3.2+py3.9的靓号管理系统python源码+学习笔记.zip
zuul源码学习添加笔记,官方项目代码_ZuulC
本资料“Spring学习笔记&源码”是基于网易云课堂黑马程序员的Spring四天精通课程,旨在帮助学习者深入理解和实践Spring框架。 笔记部分可能会涵盖以下内容: 1. **Spring概述**:介绍Spring框架的历史、特点和主要...
本笔记旨在深入解析Spring的高级源码,帮助程序员从应用层面过渡到源码级的理解。 Spring的核心组件包括Bean容器、AOP代理、数据访问/集成、MVC、Web服务等。首先,我们来探讨Bean容器,它是Spring的基础,负责管理...
微信小程序 云笔记 (源码)微信小程序 云笔记 (源码)微信小程序 云笔记 (源码)微信小程序 云笔记 (源码)微信小程序 云笔记 (源码)微信小程序 云笔记 (源码)微信小程序 云笔记 (源码)微信小程序 云笔记 (源码)微信小...
微信小程序源码 云笔记(学习版)微信小程序源码 云笔记(学习版)微信小程序源码 云笔记(学习版)微信小程序源码 云笔记(学习版)微信小程序源码 云笔记(学习版)微信小程序源码 云笔记(学习版)微信小程序源码 云笔记(学习...
【Java学习笔记(源码)】是一份详细记录了Java编程语言学习过程的资源集合,包含实际的源代码示例。这份笔记旨在帮助初学者和有一定经验的开发者深入理解和掌握Java语言的核心概念、语法以及常见应用。以下是笔记中...
为知笔记开源项目程序源码,实现云笔记功能需要自己搭建服务器 为知笔记开源项目程序源码,实现云笔记功能需要自己搭建服务器 为知笔记开源项目程序源码,实现云笔记功能需要自己搭建服务器 为知笔记开源项目程序...
学习Ruby的笔记以及Demo源码.zip学习Ruby的笔记以及Demo源码.zip学习Ruby的笔记以及Demo源码.zip学习Ruby的笔记以及Demo源码.zip学习Ruby的笔记以及Demo源码.zip学习Ruby的笔记以及Demo源码.zip学习Ruby的笔记以及...
Android最流行的网络请求框架OkHttp的源码的阅读笔记; 详细解读了请求的构建以及执行流程,应用的设计模式以及该设计模式的应用场景等
在深入学习Mybatis源码的过程中,我们可以了解到它的工作原理,更好地优化数据库交互,提高程序性能。 1. **Mybatis概述** Mybatis 源码的学习可以帮助开发者理解其内部机制,包括动态SQL的解析、SQL映射文件与...
统计学习方法笔记-基于Python算法实现源码.zip 统计学习方法笔记-基于Python算法实现源码.zip 统计学习方法笔记-基于Python算法实现源码.zip 统计学习方法笔记-基于Python算法实现源码.zip 统计学习方法笔记-基于...
STL源码剖析读书笔记 STL(Standard Template Library)的源码剖析读书笔记是对经典著作的总结,涵盖了STL的六大组件、空间分配器、迭代器、仿函式、适配器和容器等知识点。 1. 六大组件 STL提供六大组件,彼此...
《nginx源码学习笔记》.pdf
在深入探讨Hibernate学习笔记第二天的源码之前,我们先来理解一下Hibernate的核心概念。Hibernate是一个开源的对象关系映射(ORM)框架,它允许Java开发者将数据库操作转化为对象模型,大大简化了数据访问层的开发...
PHP个人学习笔记