用androidpn来实现推送
真正解决了服务器重启客户端无法连接的bug
android端修改XmppManager这个类
package org.androidpn.client; import java.util.ArrayList; import java.util.List; import java.util.UUID; import java.util.concurrent.Future; import org.jivesoftware.smack.ConnectionConfiguration; import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode; import org.jivesoftware.smack.ConnectionListener; import org.jivesoftware.smack.PacketListener; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.filter.AndFilter; import org.jivesoftware.smack.filter.PacketFilter; import org.jivesoftware.smack.filter.PacketIDFilter; import org.jivesoftware.smack.filter.PacketTypeFilter; import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.Packet; import org.jivesoftware.smack.packet.Registration; import org.jivesoftware.smack.provider.ProviderManager; import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.os.Handler; import android.util.Log; /** * This class is to manage the XMPP connection between client and server. * * @author Sehwan Noh (devnoh@gmail.com) */ public class XmppManager { private static final String LOGTAG = LogUtil.makeLogTag(XmppManager.class); private static final String XMPP_RESOURCE_NAME = "AndroidpnClient"; private Context context; private NotificationService.TaskSubmitter taskSubmitter; private NotificationService.TaskTracker taskTracker; private SharedPreferences sharedPrefs; private String xmppHost; private int xmppPort; private XMPPConnection connection; private String username; private String password; private ConnectionListener connectionListener; private PacketListener notificationPacketListener; private Handler handler; private List<Runnable> taskList; private boolean running = false; private Future<?> futureTask; private Thread reconnection; public XmppManager(NotificationService notificationService) { context = notificationService; taskSubmitter = notificationService.getTaskSubmitter(); taskTracker = notificationService.getTaskTracker(); sharedPrefs = notificationService.getSharedPreferences(); xmppHost = sharedPrefs.getString(Constants.XMPP_HOST, "localhost"); xmppPort = sharedPrefs.getInt(Constants.XMPP_PORT, 5222); username = sharedPrefs.getString(Constants.XMPP_USERNAME, ""); password = sharedPrefs.getString(Constants.XMPP_PASSWORD, ""); connectionListener = new PersistentConnectionListener(this); notificationPacketListener = new NotificationPacketListener(this); handler = new Handler(); taskList = new ArrayList<Runnable>(); reconnection = new ReconnectionThread(this); } public Context getContext() { return context; } public void connect() { Log.d(LOGTAG, "connect()..."); submitLoginTask(); } public void disconnect() { Log.d(LOGTAG, "disconnect()..."); terminatePersistentConnection(); } public void terminatePersistentConnection() { Log.d(LOGTAG, "terminatePersistentConnection()..."); Runnable runnable = new Runnable() { final XmppManager xmppManager = XmppManager.this; public void run() { if (xmppManager.isConnected()) { Log.d(LOGTAG, "terminatePersistentConnection()... run()"); xmppManager.getConnection().removePacketListener( xmppManager.getNotificationPacketListener()); xmppManager.getConnection().disconnect(); } xmppManager.runTask(); } }; addTask(runnable); } public XMPPConnection getConnection() { return connection; } public void setConnection(XMPPConnection connection) { this.connection = connection; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public ConnectionListener getConnectionListener() { return connectionListener; } public PacketListener getNotificationPacketListener() { return notificationPacketListener; } public void startReconnectionThread() { synchronized (reconnection) { if (!reconnection.isAlive()) { reconnection.setName("Xmpp Reconnection Thread"); reconnection.start(); } } } public Handler getHandler() { return handler; } public void reregisterAccount() { removeAccount(); submitLoginTask(); runTask(); } public List<Runnable> getTaskList() { return taskList; } public Future<?> getFutureTask() { return futureTask; } public void runTask() { Log.d(LOGTAG, "runTask()..."); synchronized (taskList) { running = false; futureTask = null; if (!taskList.isEmpty()) { Runnable runnable = (Runnable) taskList.get(0); taskList.remove(0); running = true; futureTask = taskSubmitter.submit(runnable); if (futureTask == null) { taskTracker.decrease(); } } } taskTracker.decrease(); Log.d(LOGTAG, "runTask()...done"); } private String newRandomUUID() { String uuidRaw = UUID.randomUUID().toString(); return uuidRaw.replaceAll("-", ""); } private boolean isConnected() { return connection != null && connection.isConnected(); } private boolean isAuthenticated() { return connection != null && connection.isConnected() && connection.isAuthenticated(); } private boolean isRegistered() { return sharedPrefs.contains(Constants.XMPP_USERNAME) && sharedPrefs.contains(Constants.XMPP_PASSWORD); } private void submitConnectTask() { Log.d(LOGTAG, "submitConnectTask()..."); addTask(new ConnectTask()); } private void submitRegisterTask() { Log.d(LOGTAG, "submitRegisterTask()..."); submitConnectTask(); addTask(new RegisterTask()); } private void submitLoginTask() { Log.d(LOGTAG, "submitLoginTask()..."); submitRegisterTask(); addTask(new LoginTask()); } private void addTask(Runnable runnable) { Log.d(LOGTAG, "addTask(runnable)..."); taskTracker.increase(); synchronized (taskList) { if (taskList.isEmpty() && !running) { running = true; futureTask = taskSubmitter.submit(runnable); if (futureTask == null) { taskTracker.decrease(); } } else { taskList.add(runnable); } } Log.d(LOGTAG, "addTask(runnable)... done"); } private void removeAccount() { Editor editor = sharedPrefs.edit(); editor.remove(Constants.XMPP_USERNAME); editor.remove(Constants.XMPP_PASSWORD); editor.commit(); } /** * A runnable task to connect the server. */ private class ConnectTask implements Runnable { final XmppManager xmppManager; private ConnectTask() { this.xmppManager = XmppManager.this; } public void run() { Log.i(LOGTAG, "ConnectTask.run()..."); if (!xmppManager.isConnected()) { // Create the configuration for this new connection ConnectionConfiguration connConfig = new ConnectionConfiguration( xmppHost, xmppPort); // connConfig.setSecurityMode(SecurityMode.disabled); connConfig.setSecurityMode(SecurityMode.required); connConfig.setSASLAuthenticationEnabled(false); connConfig.setCompressionEnabled(false); XMPPConnection connection = new XMPPConnection(connConfig); xmppManager.setConnection(connection); try { // Connect to the server connection.connect(); Log.i(LOGTAG, "XMPP connected successfully"); // packet provider ProviderManager.getInstance().addIQProvider("notification", "androidpn:iq:notification", new NotificationIQProvider()); } catch (XMPPException e) { Log.e(LOGTAG, "XMPP connection failed", e); } xmppManager.runTask(); } else { Log.i(LOGTAG, "XMPP connected already"); xmppManager.runTask(); } } } /** * A runnable task to register a new user onto the server. */ private class RegisterTask implements Runnable { final XmppManager xmppManager; private RegisterTask() { xmppManager = XmppManager.this; } public void run() { Log.i(LOGTAG, "RegisterTask.run()..."); if (!xmppManager.isRegistered()) { final String newUsername = newRandomUUID(); final String newPassword = newRandomUUID(); Registration registration = new Registration(); PacketFilter packetFilter = new AndFilter(new PacketIDFilter( registration.getPacketID()), new PacketTypeFilter( IQ.class)); PacketListener packetListener = new PacketListener() { public void processPacket(Packet packet) { Log.d("RegisterTask.PacketListener", "processPacket()....."); Log.d("RegisterTask.PacketListener", "packet=" + packet.toXML()); if (packet instanceof IQ) { IQ response = (IQ) packet; if (response.getType() == IQ.Type.ERROR) { if (!response.getError().toString().contains( "409")) { Log.e(LOGTAG, "Unknown error while registering XMPP account! " + response.getError() .getCondition()); } } else if (response.getType() == IQ.Type.RESULT) { xmppManager.setUsername(newUsername); xmppManager.setPassword(newPassword); Log.d(LOGTAG, "username=" + newUsername); Log.d(LOGTAG, "password=" + newPassword); Editor editor = sharedPrefs.edit(); editor.putString(Constants.XMPP_USERNAME, newUsername); editor.putString(Constants.XMPP_PASSWORD, newPassword); editor.commit(); Log .i(LOGTAG, "Account registered successfully"); xmppManager.runTask(); } } } }; connection.addPacketListener(packetListener, packetFilter); registration.setType(IQ.Type.SET); // registration.setTo(xmppHost); // Map<String, String> attributes = new HashMap<String, String>(); // attributes.put("username", rUsername); // attributes.put("password", rPassword); // registration.setAttributes(attributes); registration.addAttribute("username", newUsername); registration.addAttribute("password", newPassword); connection.sendPacket(registration); } else { Log.i(LOGTAG, "Account registered already"); xmppManager.runTask(); } } } /** * A runnable task to log into the server. */ private class LoginTask implements Runnable { final XmppManager xmppManager; private LoginTask() { this.xmppManager = XmppManager.this; } public void run() { Log.i(LOGTAG, "LoginTask.run()..."); if (!xmppManager.isAuthenticated()) { Log.d(LOGTAG, "username=" + username); Log.d(LOGTAG, "password=" + password); try { xmppManager.getConnection().login( xmppManager.getUsername(), xmppManager.getPassword(), XMPP_RESOURCE_NAME); Log.d(LOGTAG, "Loggedn in successfully"); // connection listener if (xmppManager.getConnectionListener() != null) { xmppManager.getConnection().addConnectionListener( xmppManager.getConnectionListener()); } // packet filter PacketFilter packetFilter = new PacketTypeFilter( NotificationIQ.class); // packet listener PacketListener packetListener = xmppManager .getNotificationPacketListener(); connection.addPacketListener(packetListener, packetFilter); //判断是否处于连接状态(添加) if(!getConnection().isConnected()) { xmppManager.runTask(); } xmppManager.runTask(); } catch (XMPPException e) { Log.e(LOGTAG, "LoginTask.run()... xmpp error"); Log.e(LOGTAG, "Failed to login to xmpp server. Caused by: " + e.getMessage()); String INVALID_CREDENTIALS_ERROR_CODE = "401"; String errorMessage = e.getMessage(); if (errorMessage != null && errorMessage .contains(INVALID_CREDENTIALS_ERROR_CODE)) { xmppManager.reregisterAccount(); return; } xmppManager.startReconnectionThread(); } catch (Exception e) { Log.e(LOGTAG, "LoginTask.run()... other error"); Log.e(LOGTAG, "Failed to login to xmpp server. Caused by: " + e.getMessage()); xmppManager.startReconnectionThread(); } //添加 xmppManager.runTask(); } else { Log.i(LOGTAG, "Logged in already"); xmppManager.runTask(); } } } }
新添加代码344-348行和369行
1.运行客户端代码,需要注意的是把androidpn.properties中的xmppHost改为你的服务器ip地址
2.服务端 jdbc.properties修改mysql数据库连接
项目部署(服务器)
首先,我单独启动一个新的tomcat,将server端部署到这下面,修改配置文件config。properties,jdbc.properties。jdbc.properties这个文件是配置你本地数据库的参数的,不能有错。启动后,简单测试成功,在自己项目中使用http协议将数据POST到server端这个org.androidpn.server.console.controller.NotificationController类的send方法中。具体参数名称及获取参数的代码,可以修改server端。基本上,写到这里的话,应该可以满足项目需求了。如果你还需要将哪些用户在线的功能整合到你自己项目中。那你就得自己跟踪下代码了。
apiKey默认1234567890为了安全在config.properties里修改
NotificationController.java代码
/* * Copyright (C) 2010 Moduad Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.androidpn.server.console.controller; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.androidpn.server.util.Config; import org.androidpn.server.xmpp.push.NotificationManager; import org.springframework.web.bind.ServletRequestUtils; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.multiaction.MultiActionController; /** * A controller class to process the notification related requests. * * @author Sehwan Noh (devnoh@gmail.com) */ public class NotificationController extends MultiActionController { private NotificationManager notificationManager; public NotificationController() { notificationManager = new NotificationManager(); } public ModelAndView list(HttpServletRequest request, HttpServletResponse response) throws Exception { ModelAndView mav = new ModelAndView(); // mav.addObject("list", null); mav.setViewName("notification/form"); return mav; } public ModelAndView send(HttpServletRequest request, HttpServletResponse response) throws Exception { String broadcast = ServletRequestUtils.getStringParameter(request, "broadcast", "Y"); String username = ServletRequestUtils.getStringParameter(request, "username"); String title = ServletRequestUtils.getStringParameter(request, "title"); String message = ServletRequestUtils.getStringParameter(request, "message"); String uri = ServletRequestUtils.getStringParameter(request, "uri"); String apiKey = Config.getString("apiKey", ""); logger.debug("apiKey=" + apiKey); if (broadcast.equalsIgnoreCase("Y")) { notificationManager.sendBroadcast(apiKey, title, message, uri); } else { notificationManager.sendNotifcationToUser(apiKey, username, title, message, uri); } ModelAndView mav = new ModelAndView(); mav.setViewName("redirect:notification.do"); return mav; } }
参考博文:
真正解决了服务器重启客户端无法连接的bug
http://www.cnblogs.com/cnblogs-lin/archive/2012/04/28/AndroidXmpp.html
源码分析
http://www.cnblogs.com/sunzn/archive/2013/02/04/2891390.html
都是用myeclipse构建的
只有tomcat
http://www.iteye.com/topic/1117043
jetty和tomcat
http://mobile.51cto.com/aprogram-403300.htm
myeclipse发布对应关系