OpenFire源码学习之二十二:openfie对用户的优化(下)

本文介绍使用Redis优化用户名片存储及用户搜索功能的方法。通过自定义RedisVCardProvider类实现用户名片的高效读写,并利用Redis进行用户信息的分词存储与快速检索。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

用户名片

在预初始化中,贴出来用户名片的程序。这里也一样不在重复。

首先同样先修改系统属性:

provider.vcard.className

org.jivesoftware.util.redis.expand.RedisVCardProvider

然后需要修改VCardManager名片管理这个类。

RedisVCardProvider:

[java]  view plain  copy
  1. import redis.clients.jedis.Jedis;  
  2. public class RedisVCardProvider implements VCardProvider {  
  3.   
  4.     private static final Logger Log = LoggerFactory.getLogger(RedisVCardProvider.class);  
  5.       
  6.     private static final String DELETE_PROPERTIES =  
  7.         "DELETE FROM ofVCard WHERE username=?";  
  8.     private static final String UPDATE_PROPERTIES =  
  9.         "UPDATE ofVCard SET vcard=? WHERE username=?";  
  10.     private static final String INSERT_PROPERTY =  
  11.         "INSERT INTO ofVCard (username, vcard) VALUES (?, ?)";  
  12.       
  13.     private static final int POOL_SIZE = 10;  
  14.       
  15.     private BlockingQueue<SAXReader> xmlReaders = new LinkedBlockingQueue<SAXReader>(POOL_SIZE);  
  16.       
  17.     public RedisVCardProvider() {  
  18.         super();  
  19.         // Initialize the pool of sax readers  
  20.         for (int i=0; i<POOL_SIZE; i++) {  
  21.             SAXReader xmlReader = new SAXReader();  
  22.             xmlReader.setEncoding("UTF-8");  
  23.             xmlReaders.add(xmlReader);  
  24.         }  
  25.     }  
  26.       
  27.     @Override  
  28.     public Element loadVCard(String username) {  
  29.         synchronized (username.intern()) {  
  30.             Jedis jedis = XMPPServer.getInstance().getUserJedis().getJedis();  
  31.             Element vCardElement = null;  
  32.             SAXReader xmlReader = null;  
  33.             try {  
  34.                 // Get a sax reader from the pool  
  35.                 xmlReader = xmlReaders.take();  
  36.                 String usercard = jedis.get("OFVCARD:" + username);  
  37.                 if (usercard == null || "".equals(usercard)) {  
  38.                     return XMPPServer.getInstance().getJedisConfDao().getVCardProvider().loadVCard(username);  
  39.                 }  
  40.                 vCardElement = xmlReader.read(new StringReader(usercard)).getRootElement();  
  41.             }  
  42.             catch (Exception e) {  
  43.                 Log.error("Error loading vCard of username: " + username, e);  
  44.             }  
  45.             finally {  
  46.                 if (xmlReader != null) {  
  47.                     xmlReaders.add(xmlReader);  
  48.                 }  
  49.                 XMPPServer.getInstance().getUserJedis().returnRes(jedis);  
  50.             }  
  51.             return vCardElement;  
  52.         }  
  53.     }  
  54.   
  55.     @Override  
  56.     public Element createVCard(String username, Element vCardElement)  
  57.             throws AlreadyExistsException {  
  58.         ......  
  59.     }  
  60.   
  61.     @Override  
  62.     public Element updateVCard(String username, Element vCardElement)  
  63.             throws NotFoundException {  
  64.         ......  
  65.     }  
  66.   
  67.     @Override  
  68.     public void deleteVCard(String username) {  
  69.         ......  
  70.     }  
  71.     @Override  
  72.     public boolean isReadOnly() {  
  73.         // TODO Auto-generated method stub  
  74.         return false;  
  75.     }  
  76. }  

VCardManager

[java]  view plain  copy
  1. /** 
  2.  * Manages VCard information for users. 
  3.  * 
  4.  * @author Matt Tucker 
  5.  */  
  6. public class VCardManager extends BasicModule implements ServerFeaturesProvider {  
  7.   
  8.     private static final Logger Log = LoggerFactory.getLogger(VCardManager.class);  
  9.       
  10.     private VCardProvider provider;  
  11.       
  12.     private static VCardManager instance;  
  13.       
  14.     private EventHandler eventHandler;  
  15.       
  16.     private static HmThreadPool threadPool = new HmThreadPool(5);  
  17.       
  18.     public static VCardManager getInstance() {  
  19.         return instance;  
  20.     }  
  21.       
  22.     public static VCardProvider getProvider() {  
  23.         return instance.provider;  
  24.     }  
  25.       
  26.     public VCardManager() {  
  27.         super("VCard Manager");  
  28.         //String cacheName = "VCard";  
  29.         //vcardCache = CacheFactory.createCache(cacheName);  
  30.         this.eventHandler = new EventHandler();  
  31.   
  32.         // Keeps the cache updated in case the vCard action was not performed by VCardManager  
  33.         VCardEventDispatcher.addListener(new VCardListener() {  
  34.             public void vCardCreated(String username, Element vCard) {  
  35.                 // Since the vCard could be created by the provider, add it to the cache.  
  36.                 //vcardCache.put(username, vCard);  
  37.                 Jedis jedis = XMPPServer.getInstance().getUserJedis().getJedis();  
  38.                 try {  
  39.                     jedis.set("OFVCARD:" + username, vCard.asXML());  
  40.                 } finally {  
  41.                     XMPPServer.getInstance().getUserJedis().returnRes(jedis);  
  42.                 }  
  43.             }  
  44.   
  45.             public void vCardUpdated(String username, Element vCard) {  
  46.                 // Since the vCard could be updated by the provider, update it to the cache.  
  47.                 //vcardCache.put(username, vCard);  
  48.                 vCardCreated(username, vCard);  
  49.             }  
  50.   
  51.             public void vCardDeleted(String username, Element vCard) {  
  52.                 // Since the vCard could be delated by the provider, remove it to the cache.  
  53.                 //vcardCache.remove(username);  
  54.                 Jedis jedis = XMPPServer.getInstance().getUserJedis().getJedis();  
  55.                   
  56.                 try {  
  57.                     jedis.del("OFVCARD:" + username);  
  58.                 } finally {  
  59.                     XMPPServer.getInstance().getUserJedis().returnRes(jedis);  
  60.                 }  
  61.             }  
  62.         });  
  63.     }  
  64.   
  65.     public String getVCardProperty(String username, String name) {  
  66.         ......  
  67.     }  
  68.       
  69.     public void setVCard(String username, Element vCardElement) throws Exception {  
  70.         boolean created = false;  
  71.         boolean updated = false;  
  72.   
  73.         if (provider.isReadOnly()) {  
  74.             throw new UnsupportedOperationException("VCard provider is read-only.");  
  75.         }  
  76.           
  77.         //Element newvCard = null;  
  78.         Jedis jedis = XMPPServer.getInstance().getUserJedis().getJedis();  
  79.         try {  
  80.             boolean exists = jedis.exists("OFVCARD:" + username);  
  81.               
  82.             if (exists) {  
  83.                 threadPool.execute(createTaskByUpdateVCard(provider, username, vCardElement));  
  84.                 updated = true;  
  85.             }  
  86.             else {  
  87.                 threadPool.execute(createTaskByCreateVCard(provider, username, vCardElement));  
  88.                 created = true;  
  89.             }  
  90.         }finally {  
  91.             XMPPServer.getInstance().getUserJedis().returnRes(jedis);  
  92.         }  
  93.         // Dispatch vCard events  
  94.         if (created) {   
  95.             // Alert listeners that a new vCard has been created  
  96.             VCardEventDispatcher.dispatchVCardCreated(username, vCardElement);  
  97.         } else if (updated) {  
  98.             // Alert listeners that a vCard has been updated  
  99.             VCardEventDispatcher.dispatchVCardUpdated(username, vCardElement);  
  100.         }  
  101.     }  
  102.       
  103.     private Runnable createTaskByCreateVCard(final VCardProvider provider, final String username,   
  104.             final Element vCardElement) {     
  105.         return new Runnable() {     
  106.             public void run() {  
  107.                 try {  
  108.                     provider.createVCard(username, vCardElement);  
  109.                 } catch (AlreadyExistsException e) {  
  110.                     Log.error("AlreadyExistsException: username=" + username + ", vCardElement=" + vCardElement);  
  111.                 }  
  112.             }     
  113.         };     
  114.     }   
  115.       
  116.     private Runnable createTaskByUpdateVCard(final VCardProvider provider, final String username,   
  117.             final Element vCardElement) {     
  118.         return new Runnable() {     
  119.             public void run() {  
  120.                 try {  
  121.                     provider.updateVCard(username, vCardElement);  
  122.                 } catch (NotFoundException e) {  
  123.                     Log.error("NotFoundException: username=" + username + ", vCardElement=" + vCardElement);  
  124.                 }  
  125.             }     
  126.         };     
  127.     }  
  128.       
  129.     public void deleteVCard(String username) {  
  130.         if (provider.isReadOnly()) {  
  131.             throw new UnsupportedOperationException("VCard provider is read-only.");  
  132.         }  
  133.           
  134.         final String vusername = username;  
  135.         threadPool.execute(new Runnable() {  
  136.             @Override  
  137.             public void run() {  
  138.                 provider.deleteVCard(vusername);  
  139.             }  
  140.         });  
  141.         VCardEventDispatcher.dispatchVCardDeleted(username, null);  
  142.     }  
  143.       
  144.       
  145.     public Element getVCard(String username) {  
  146.         Element vCardElement = getOrLoadVCard(username);  
  147.         return vCardElement == null ? null : vCardElement.createCopy();  
  148.     }  
  149.       
  150.     private Element getOrLoadVCard(String username) {  
  151.         return provider.loadVCard(username);  
  152.     }  
  153.       
  154.     @Override  
  155.     public void initialize(XMPPServer server) {  
  156.         ......  
  157.     }  
  158.       
  159.     @Override  
  160.     public void start() {  
  161.         ......  
  162.     }  
  163.       
  164.     @Override  
  165.     public void stop() {  
  166.         // Remove this module as a user event listener  
  167.         UserEventDispatcher.removeListener(eventHandler);  
  168.     }  
  169.       
  170.     public void reset() {  
  171.         //vcardCache.clear();  
  172.     }  
  173.       
  174.     @Override  
  175.     public Iterator<String> getFeatures() {  
  176.         ArrayList<String> features = new ArrayList<String>();  
  177.         features.add("redis-vcard-temp");  
  178.         return features.iterator();  
  179.     }  
  180.   
  181.     private class EventHandler extends UserEventAdapter {  
  182.         @Override  
  183.         public void userDeleting(User user, Map params) {  
  184.             try {  
  185.                 deleteVCard(user.getUsername());  
  186.             } catch (UnsupportedOperationException ue) { /* Do Nothing */ }  
  187.         }  
  188.     }  
  189.       
  190.     public UserCardEnity getUserCardByUserName (String username) {  
  191.         Element element = getVCard(username);  
  192.         UserCardEnity uce = new UserCardEnity();  
  193.           
  194.         if (element != null) {  
  195.             String myName = element.elementText("MYNAME");  
  196.             String sex = element.elementText("SEX");  
  197.             String oname = element.elementText("ONAME");  
  198.             String moblie = element.elementText("MOBILE");  
  199.             String landline = element.elementText("LANDLINE");  
  200.             String address = element.elementText("ADDRESS");  
  201.             String workUnit = element.elementText("WORKUNIT");  
  202.             String birthday = element.elementText("BIRTHDAY");  
  203.             String photo = element.elementText("PHOTO");  
  204.             String userType = element.elementText("USERTYPE");  
  205.               
  206.             uce.setMyName( myName);  
  207.             uce.setSex(sex);  
  208.             uce.setOname(oname);  
  209.             uce.setMoblie( moblie) ;  
  210.             uce.setLandline(landline);  
  211.             uce.setAddress(address);  
  212.             uce.setWorkUnit(workUnit) ;  
  213.             uce.setBirthday(birthday);  
  214.             uce.setPhoto(photo);  
  215.               
  216.             if (userType == null) {  
  217.                 uce.setUserType("");  
  218.             }  
  219.             else if (1 == Integer.valueOf(userType)) {  
  220.                 uce.setUserType("student");  
  221.             }  
  222.             else if (2 == Integer.valueOf(userType)) {  
  223.                 uce.setUserType("teacher");  
  224.             }  
  225.             else if (3 == Integer.valueOf(userType)) {  
  226.                 uce.setUserType("Guardian");  
  227.             }  
  228.             else if (4 == Integer.valueOf(userType)) {  
  229.                 uce.setUserType("edusun admin");  
  230.             }  
  231.             else if (5 == Integer.valueOf(userType)) {  
  232.                 uce.setUserType("Agents");  
  233.             }  
  234.             else {  
  235.                 uce.setUserType("Other locations");  
  236.             }  
  237.         }  
  238.         return uce;  
  239.     }  
  240. }  

用户名片就到这了。

用户搜索

搜索用户的时候,在openfire中都是重新查找关系数据库的。因为我们已经将用户预加载到了redis中。那么这里只需要对用户做一些分词存储检索即可。

本人在这里做了比较简单的分词处理。比如用户名,手机号码等。

首先要做的就是制作用户分词了。然后要做的就是需要修修改搜索的handler处理类。Openfire上提供了一个search搜索插件。查询消息最后提交给SearchPlugin这个类的handler方法。本人这里就不做描述。重点要说的就是如何在redis中分词存储。

客户端发送用户查找请求如下:

[html]  view plain  copy
  1. <iq id="E6l1b-43" to="test@search.hytest240" type="get"><query xmlns="jabber:iq:search"></query></iq>  

请看代码清单:

RedisSearchManager:

[java]  view plain  copy
  1. public class RedisSearchManager extends BasicModule{  
  2.   
  3.     private static final Logger LOG = LoggerFactory.getLogger(RedisSearchManager.class);  
  4.   
  5.     private static final Integer timeout = 1000*10;  
  6.     private static final int maxActive = 5000 * 10;  
  7.     private static final int maxIdle = 5;  
  8.     private static final long maxWait = (1000 * 100);  
  9.       
  10.     private static JedisPool pool;  
  11.     private static XMPPServer loaclserver;  
  12.     private static JedisPoolConfig config;  
  13.       
  14.     public RedisSearchManager() {  
  15.         super("Redis search manager");  
  16.     }  
  17.       
  18.     private static JedisPoolConfig createConfig() {  
  19.            ......  
  20.     }  
  21.       
  22.     private static void createJedisPool() {  
  23.         ......//创建连接池  
  24.     }  
  25.   
  26.     private static synchronized void poolInit() {  
  27.         boolean enabled = JiveGlobals.getBooleanProperty("plugin.userservice.enabled");  
  28.         if (enabled) {  
  29.             if (pool == null)  
  30.                 createJedisPool();  
  31.         }  
  32.     }  
  33.   
  34.     public Jedis getSearchJedis() {  
  35.         if (pool == null)  
  36.             poolInit();  
  37.         Jedis jedis = pool.getResource();  
  38.         jedis.select(3);  
  39.         return jedis;  
  40.     }  
  41.   
  42.     public void returnSearchJedis(Jedis jedis) {  
  43.         pool.returnResource(jedis);  
  44.     }  
  45.       
  46.     @Override  
  47.     public void initialize(XMPPServer server) {  
  48. .....  
  49.     }  
  50.       
  51.     //创建用户的搜索关键词数据  
  52.     public void createSearchAllUserData() {  
  53.         Collection<User> userList = XMPPServer.getInstance().getUserJedis().getAllUser();  
  54.         for (User user : userList) {  
  55.             createSearchUserData(user);  
  56.         }  
  57.         System.out.println("Initialize the user search data is completed...(the end)");  
  58.     }  
  59.       
  60.    //这里根据string长度切分。按照“|”分割  
  61.     public void createSearchUserData(User user) {  
  62.         Jedis jedis = getSearchJedis();  
  63.         IndexWriter iw = new IndexWriter(jedis);  
  64.         String username = user.getUsername();  
  65.         String keyword = "";  
  66.         if (username.length() >= 4) {  
  67.             int index = 4;  
  68.             for (int i=0; i<=username.length()-4; i++) {  
  69.                 String usernameKey = username.substring(0, index++) + "|";  
  70.                 keyword += usernameKey;  
  71.             }  
  72.         }  
  73.         else {  
  74.             keyword = username + "|";  
  75.         }  
  76.           
  77.         if (user.getName() != null && !"".equals(user.getName())) {  
  78.             keyword += user.getName() + "|";  
  79.         }  
  80.         if (user.getEmail() != null && !"".equals(user.getEmail())) {  
  81.             keyword += user.getEmail() + "|";  
  82.         }  
  83.         if (user.getMoblie() != null && !"".equals(user.getMoblie())) {  
  84.             keyword += user.getMoblie();  
  85.         }  
  86.           
  87.   
  88.         if ("|".equals(keyword.substring(keyword.length()-1))) {  
  89.             keyword = keyword.substring(0, keyword.length()-1);  
  90.         }  
  91.           
  92.         iw.addIdAndIndexItem(username, keyword);  
  93.         iw.addNeedSortItem("USERNAME",username);  
  94.         iw.addNeedSortItem("CREATIONDATE",user.getCreationDate() != null ? user.getCreationDate() : StringUtils.dateToMillis(new Date()));  
  95.         iw.addNeedSortItem("MODIFICATIONDATE",user.getModificationDate() != null ? user.getModificationDate() : StringUtils.dateToMillis(new Date()));  
  96.         iw.writer();  
  97.         System.out.println("create user search data, id:" + username + ", keyword:" + keyword);  
  98.         LOG.info("create user search data, id:" + username + ", keyword:" + keyword);  
  99.         returnSearchJedis(jedis);  
  100.     }   
  101. }  

IndexWriter写入索引

[java]  view plain  copy
  1. public class IndexWriter {  
  2.     private Jedis jedis;  
  3.     private String id;  
  4.     private Map<String, String> items = new HashMap<String, String>();  
  5.     private String contentItems[];  
  6.   
  7.     public IndexWriter(Jedis jedis) {  
  8.         if (!jedis.isConnected()) {  
  9.             jedis.connect();  
  10.         }  
  11.         this.jedis = jedis;  
  12.     }  
  13.     /** 
  14.      * @param id 
  15.      *            必须有 
  16.      * @param content 
  17.      *            是分词程序切分后的内容,每个词中间必须用用“|”分隔,如:中国|中国人|2012 
  18.      */  
  19.     public void addIdAndIndexItem(String id, String content) {  
  20.         this.id = id;  
  21.         contentItems = content.split("\\|");  
  22.     }  
  23.     public void addNeedSortItem(String name, String value) {  
  24.         items.put(name, value);  
  25.     }  
  26.     public void writer() {  
  27.         indexWriter();  
  28.         itemWriter();  
  29.     }  
  30.     private void indexWriter() {  
  31.         if (!id.equals("") && contentItems.length != 0) {  
  32.             for (int i = 0; i < contentItems.length; i++) {  
  33.                 jedis.sadd(contentItems[i].trim(), id);  
  34.             }  
  35.         }  
  36.     }  
  37.     private void itemWriter() {  
  38.         if (items.size() != 0) {  
  39.             Iterator<Entry<String, String>> it = items.entrySet().iterator();  
  40.             while (it.hasNext()) {  
  41.                 Entry<String, String> entry = (Entry<String, String>) it.next();  
  42.                 jedis.set(entry.getKey().toString() + ":" + id, entry  
  43.                         .getValue().toString());  
  44.             }  
  45.         }  
  46.     }  
  47. }  

IndexSearch:查找索引

[java]  view plain  copy
  1. public class IndexSearch {  
  2.     public static int ALPHA = 0;  
  3.     public static int DESC = 1;  
  4.     public static int ASC = 2;  
  5.   
  6.     private Jedis jedis;  
  7.     private int limit = 100;  
  8.     private String itemName = null;  
  9.     private int pager = 0;  
  10.   
  11.     public IndexSearch(Jedis jedis) {  
  12.         if (!jedis.isConnected()) {  
  13.             jedis.connect();  
  14.         }  
  15.         this.jedis = jedis;  
  16.     }  
  17.   
  18.     private SortingParams getSP(String item, int sort) {  
  19.         SortingParams sp = new SortingParams();  
  20.         sp.limit(pager, limit);  
  21.   
  22.         if (null == item || "".equals(item)) {  
  23.             switch (sort) {  
  24.             case 1:  
  25.                 sp.desc();  
  26.                 break;  
  27.             case 2:  
  28.                 sp.asc();  
  29.                 break;  
  30.             case 0:  
  31.             default:  
  32.                 sp.alpha();  
  33.                 break;  
  34.             }  
  35.         } else {  
  36.             switch (sort) {  
  37.             case 1:  
  38.                 sp.by(itemName + ":*").desc();  
  39.                 break;  
  40.             case 2:  
  41.                 sp.by(itemName + ":*").asc();  
  42.                 break;  
  43.             case 0:  
  44.             default:  
  45.                 sp.by(itemName + ":*").alpha();  
  46.                 break;  
  47.             }  
  48.         }  
  49.         return sp;  
  50.     }  
  51.   
  52.     private List<String> isearch(int sort, String... query) {  
  53.         jedis.sinterstore("tempKey", query);  
  54.         return jedis.sort("tempKey"this.getSP(itemName, sort));  
  55.     }  
  56.   
  57.     public List<String> search(String... query) {  
  58.         return this.isearch(0, query);  
  59.     }  
  60.   
  61.     public List<String> search(int sort, String... query) {  
  62.         return this.isearch(sort, query);  
  63.     }  
  64.   
  65.     public List<String> search(String itemName, int sort, String... query) {  
  66.         this.itemName = itemName;  
  67.         return this.isearch(sort, query);  
  68.     }  
  69.   
  70.     public List<String> search(String itemName, int sort, int limit,  
  71.             String... query) {  
  72.         this.itemName = itemName;  
  73.         this.limit = limit;  
  74.         return this.isearch(sort, query);  
  75.     }  
  76.   
  77.     public List<String> search(String itemName, int sort, int pager, int limit,  
  78.             String... query) {  
  79.         this.itemName = itemName;  
  80.         this.limit = limit;  
  81.         this.pager = pager;  
  82.         return this.isearch(sort, query);  
  83.     }  
  84. }  

Ok用户搜索这就只贴出一些比较关键性的代码。提供思路。代码贴多了搞了篇幅很长。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值