![](http://static.blog.csdn.net/images/category_icon.jpg)
版权声明:本文为博主原创文章,未经博主允许不得转载。
今天分享一个openfire批量推送的插件,上次我们做的插件只是适合小范围推送,这次我们做一个给全部“在线”的用户推送消息的插件,只有在线用户才会收到推送消息,离线的用户不会收到消息(不会收到离线消息),如果同一账号使用多个终端登录那么多个终端都会收到推送消息。当然也可以把这个插件稍作修改就变成一个批量推送的插件,不一定要给全服的用户推送消息。
由于这次考虑到操作的用户量比较大,所以采用比较传统的方式
1. 推送的信息首先保存到数据库
2. checkThread以轮训的方式检查数据库是否有需要推送的消息
3. 有消息后创建Runnable对象并且扔到threadpool内执行
插件实现起来并不能,甚至是有一点简单,主要是如何获取数据库内的用户和如何检查用户是否在线,这两点了解的剩下的就简单了。
1. 检查是否有需要推送的消息
CheckThread.Java
个人觉得这部分是写的最失败的地方,采用的是原始的数据库轮训的机制,如果是生产环境是可以使用像Redis、activeMQ或者其他的方式来实现
- package com.xxdd.openfire.batchpush.plugin.thread;
- import java.util.List;
- import org.xmpp.component.ComponentManager;
- import org.xmpp.component.ComponentManagerFactory;
- import com.xxdd.openfire.batchpush.plugin.model.OFBatchPush;
- import com.xxdd.openfire.batchpush.plugin.model.OFUser;
- import com.xxdd.openfire.batchpush.plugin.provider.OFBatchPushProvider;
- import com.xxdd.openfire.batchpush.plugin.provider.OFUserProvider;
- public class CheckThread extends Thread {
- ComponentManager componentManager = ComponentManagerFactory.getComponentManager();
- public void run() {
- while (ThreadPool.RUNNING) {
- OFBatchPush batPush = OFBatchPushProvider.getInstance().getPushContent();
- if (batPush == null) {//没有需要推送的消息
- try {
- Thread.sleep(3000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- } else {//有需要推送的消息
- //检查数据库内用户的数量
- int count = OFUserProvider.getInstance().getUserCount();
- int len = 20;
- int maxPage = (int) Math.ceil((float) count / (float) len);
- for (int i=0; i<maxPage; i++) {
- //分页查询用户
- List<OFUser> users = OFUserProvider.getInstance().findUsers(i*len, len);
- if (users != null && users.size() > 0) {
- for (OFUser user : users) {
- //把要发送的消息内容和消息的接收人组装成Runnable对象
- PushRunnable runnable = new PushRunnable(
- user.getUsername(),
- componentManager,
- batPush.getBody()
- );
- //把runnable对象放到线程池内执行
- ThreadPool.execute(runnable);
- }
- }
- }
- //最后发送完成,在数据库内删除消息内容
- OFBatchPushProvider.getInstance().delPush(batPush.getId());
- }
- }
- }
- }
OFBatchPushProvider.java
- package com.xxdd.openfire.batchpush.plugin.provider;
- import java.sql.Connection;
- import java.sql.PreparedStatement;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- import org.jivesoftware.database.DbConnectionManager;
- import com.xxdd.openfire.batchpush.plugin.model.OFBatchPush;
- public class OFBatchPushProvider {
- private static OFBatchPushProvider self;
- private OFBatchPushProvider() {
- }
- public static OFBatchPushProvider getInstance() {
- if (self == null)
- self = new OFBatchPushProvider();
- return self;
- }
- /**
- * 获得需要推送的内容
- * @return
- */
- public OFBatchPush getPushContent() {
- String loadPushSQL = "SELECT id, body, create_time FROM ofBatchpush ORDER BY create_time LIMIT 1";
- Connection con = null;
- PreparedStatement pstmt = null;
- ResultSet rs = null;
- try {
- con = DbConnectionManager.getConnection();
- pstmt = con.prepareStatement(loadPushSQL);
- rs = pstmt.executeQuery();
- if (rs.next()) {
- OFBatchPush batPush = new OFBatchPush();
- batPush.setId(rs.getInt(1));
- batPush.setBody(rs.getString(2));
- batPush.setCreateTime(rs.getDate(3));
- return batPush;
- }
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- DbConnectionManager.closeConnection(rs, pstmt, con);
- }
- return null;
- }
- /**
- * 删除推送消息内容
- * @param id
- */
- public void delPush(int id) {
- String delPushSQL = "DELETE FROM ofBatchpush WHERE id = ?";
- Connection con = null;
- PreparedStatement pstmt = null;
- ResultSet rs = null;
- try {
- con = DbConnectionManager.getConnection();
- pstmt = con.prepareStatement(delPushSQL);
- pstmt.setInt(1,id);
- pstmt.executeUpdate();
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- DbConnectionManager.closeConnection(rs, pstmt, con);
- }
- }
- }
OFBatchPush.java
- package com.xxdd.openfire.batchpush.plugin.model;
- import java.util.Date;
- public class OFBatchPush {
- private int id;
- private String body;
- private Date createTime;
- public int getId() {
- return id;
- }
- public void setId(int id) {
- this.id = id;
- }
- public String getBody() {
- return body;
- }
- public void setBody(String body) {
- this.body = body;
- }
- public Date getCreateTime() {
- return createTime;
- }
- public void setCreateTime(Date createTime) {
- this.createTime = createTime;
- }
- }
OFUserProvider.java
- package com.xxdd.openfire.batchpush.plugin.provider;
- import java.sql.Connection;
- import java.sql.PreparedStatement;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- import java.util.ArrayList;
- import java.util.List;
- import org.jivesoftware.database.DbConnectionManager;
- import com.xxdd.openfire.batchpush.plugin.model.OFUser;
- /**
- *
- * @author xxdd
- */
- public class OFUserProvider {
- private static OFUserProvider self = null;
- private OFUserProvider() {
- }
- public static OFUserProvider getInstance() {
- if (self == null)
- self = new OFUserProvider();
- return self;
- }
- /**
- * 分页查询用户
- * @param offset
- * @param len
- * @return
- */
- public List<OFUser> findUsers(int offset, int len) {
- String loadUsersSQL = "SELECT username FROM ofUser LIMIT ?,?";
- Connection con = null;
- PreparedStatement pstmt = null;
- ResultSet rs = null;
- List<OFUser> users = new ArrayList<OFUser>(len);
- try {
- con = DbConnectionManager.getConnection();
- pstmt = con.prepareStatement(loadUsersSQL);
- pstmt.setInt(1, offset);
- pstmt.setInt(2, len);
- rs = pstmt.executeQuery();
- while (rs.next()) {
- OFUser user = new OFUser(rs.getString(1));
- users.add(user);
- }
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- DbConnectionManager.closeConnection(rs, pstmt, con);
- }
- return users;
- }
- /**
- * 获得用户总量
- * @return
- */
- public int getUserCount() {
- String loadUserCountSQL = "SELECT COUNT(1) FROM ofUser";
- Connection con = null;
- PreparedStatement pstmt = null;
- ResultSet rs = null;
- int count = 0;
- try {
- con = DbConnectionManager.getConnection();
- pstmt = con.prepareStatement(loadUserCountSQL);
- rs = pstmt.executeQuery();
- rs.next();
- count = rs.getInt(1);
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- DbConnectionManager.closeConnection(rs, pstmt, con);
- }
- return count;
- }
- }
OFUser.java
- package com.xxdd.openfire.batchpush.plugin.model;
- public class OFUser {
- private String username;
- public OFUser() {
- }
- public OFUser(String username) {
- this.username = username;
- }
- public String getUsername() {
- return username;
- }
- public void setUsername(String username) {
- this.username = username;
- }
- }
2. 线程池
使用jdk自带的executor框架,创建一个简单的线程池,网上已经有很多的例子了,这里就不啰嗦了
- package com.xxdd.openfire.batchpush.plugin.thread;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.LinkedBlockingDeque;
- import java.util.concurrent.ThreadPoolExecutor;
- import java.util.concurrent.TimeUnit;
- public class ThreadPool {
- private static ExecutorService pool = null;
- private static int minThread = 5;
- private static int maxThread = 20;
- private static LinkedBlockingDeque<Runnable> queue = new LinkedBlockingDeque<Runnable>(100);
- public static boolean RUNNING = true;
- static {
- pool = new ThreadPoolExecutor(
- minThread,
- maxThread,
- 60L,
- TimeUnit.SECONDS,
- queue,
- new ThreadPoolExecutor.CallerRunsPolicy()
- );
- RUNNING = true;
- }
- public static void execute(Runnable runnable) {
- if (RUNNING) {
- pool.execute(runnable);
- }
- }
- public static void shutDown() {
- RUNNING = false;
- pool.shutdownNow();
- }
- }
3. 发送线程
这部分代码不叫关键,是整个推送的核心部分
- package com.xxdd.openfire.batchpush.plugin.thread;
- import java.util.Collection;
- import org.jivesoftware.openfire.SessionManager;
- import org.jivesoftware.openfire.XMPPServer;
- import org.jivesoftware.openfire.session.ClientSession;
- import org.xmpp.component.ComponentException;
- import org.xmpp.component.ComponentManager;
- import org.xmpp.packet.JID;
- import org.xmpp.packet.Message;
- import org.xmpp.packet.Message.Type;
- public class PushRunnable implements Runnable {
- SessionManager sessionManager = SessionManager.getInstance();
- String toUsername;
- ComponentManager componentManager;
- String body;
- private static final String from = "system";
- private static final String domain = XMPPServer.getInstance().getServerInfo().getXMPPDomain();
- public PushRunnable(
- String toUsername,
- ComponentManager componentManager,
- String body) {
- this.toUsername = toUsername;
- this.componentManager = componentManager;
- this.body = body;
- }
- @Override
- public void run() {
- //获得在线用户session
- Collection<ClientSession> sessions = sessionManager.getSessions(toUsername);
- if (sessions != null && sessions.size() > 0) {//存在在线用户的session
- Message message = new Message();
- message.setBody(body);
- message.setFrom(from + "@" + domain);
- message.setTo(toUsername + "@" + domain);
- message.setType(Type.normal);
- //给单个用户的所有登录的客户端发送消息
- for (ClientSession session : sessions) {
- JID jid = session.getAddress();
- Message cpMessage = message.createCopy();
- cpMessage.setTo(jid);
- try {
- //给在线用户推送消息
- componentManager.sendPacket(null, message);
- } catch (ComponentException e) {
- e.printStackTrace();
- }
- }
- }
- }
- }
完整代码下载地址:http://download.csdn.NET/detail/kaixinwoo5/7579365
有问题欢迎邮件讨论7325356@qq.com