真正解决了服务器重启客户端无法连接的bug

android端修改XmppManager这个类

packageorg.androidpn.client;importjava.util.ArrayList;importjava.util.List;importjava.util.UUID;importjava.util.concurrent.Future;importorg.jivesoftware.smack.ConnectionConfiguration;importorg.jivesoftware.smack.ConnectionConfiguration.SecurityMode;importorg.jivesoftware.smack.ConnectionListener;importorg.jivesoftware.smack.PacketListener;importorg.jivesoftware.smack.XMPPConnection;importorg.jivesoftware.smack.XMPPException;importorg.jivesoftware.smack.filter.AndFilter;importorg.jivesoftware.smack.filter.PacketFilter;importorg.jivesoftware.smack.filter.PacketIDFilter;importorg.jivesoftware.smack.filter.PacketTypeFilter;importorg.jivesoftware.smack.packet.IQ;importorg.jivesoftware.smack.packet.Packet;importorg.jivesoftware.smack.packet.Registration;importorg.jivesoftware.smack.provider.ProviderManager;importandroid.content.Context;importandroid.content.SharedPreferences;importandroid.content.SharedPreferences.Editor;importandroid.os.Handler;importandroid.util.Log;/***ThisclassistomanagetheXMPPconnectionbetweenclientandserver.**@authorSehwanNoh(devnoh@gmail.com)*/publicclassXmppManager{privatestaticfinalStringLOGTAG=LogUtil.makeLogTag(XmppManager.class);privatestaticfinalStringXMPP_RESOURCE_NAME="AndroidpnClient";privateContextcontext;privateNotificationService.TaskSubmittertaskSubmitter;privateNotificationService.TaskTrackertaskTracker;privateSharedPreferencessharedPrefs;privateStringxmppHost;privateintxmppPort;privateXMPPConnectionconnection;privateStringusername;privateStringpassword;privateConnectionListenerconnectionListener;privatePacketListenernotificationPacketListener;privateHandlerhandler;privateList<Runnable>taskList;privatebooleanrunning=false;privateFuture<?>futureTask;privateThreadreconnection;publicXmppManager(NotificationServicenotificationService){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=newPersistentConnectionListener(this);notificationPacketListener=newNotificationPacketListener(this);handler=newHandler();taskList=newArrayList<Runnable>();reconnection=newReconnectionThread(this);}publicContextgetContext(){returncontext;}publicvoidconnect(){Log.d(LOGTAG,"connect()...");submitLoginTask();}publicvoiddisconnect(){Log.d(LOGTAG,"disconnect()...");terminatePersistentConnection();}publicvoidterminatePersistentConnection(){Log.d(LOGTAG,"terminatePersistentConnection()...");Runnablerunnable=newRunnable(){finalXmppManagerxmppManager=XmppManager.this;publicvoidrun(){if(xmppManager.isConnected()){Log.d(LOGTAG,"terminatePersistentConnection()...run()");xmppManager.getConnection().removePacketListener(xmppManager.getNotificationPacketListener());xmppManager.getConnection().disconnect();}xmppManager.runTask();}};addTask(runnable);}publicXMPPConnectiongetConnection(){returnconnection;}publicvoidsetConnection(XMPPConnectionconnection){this.connection=connection;}publicStringgetUsername(){returnusername;}publicvoidsetUsername(Stringusername){this.username=username;}publicStringgetPassword(){returnpassword;}publicvoidsetPassword(Stringpassword){this.password=password;}publicConnectionListenergetConnectionListener(){returnconnectionListener;}publicPacketListenergetNotificationPacketListener(){returnnotificationPacketListener;}publicvoidstartReconnectionThread(){synchronized(reconnection){if(!reconnection.isAlive()){reconnection.setName("XmppReconnectionThread");reconnection.start();}}}publicHandlergetHandler(){returnhandler;}publicvoidreregisterAccount(){removeAccount();submitLoginTask();runTask();}publicList<Runnable>getTaskList(){returntaskList;}publicFuture<?>getFutureTask(){returnfutureTask;}publicvoidrunTask(){Log.d(LOGTAG,"runTask()...");synchronized(taskList){running=false;futureTask=null;if(!taskList.isEmpty()){Runnablerunnable=(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");}privateStringnewRandomUUID(){StringuuidRaw=UUID.randomUUID().toString();returnuuidRaw.replaceAll("-","");}privatebooleanisConnected(){returnconnection!=null&&connection.isConnected();}privatebooleanisAuthenticated(){returnconnection!=null&&connection.isConnected()&&connection.isAuthenticated();}privatebooleanisRegistered(){returnsharedPrefs.contains(Constants.XMPP_USERNAME)&&sharedPrefs.contains(Constants.XMPP_PASSWORD);}privatevoidsubmitConnectTask(){Log.d(LOGTAG,"submitConnectTask()...");addTask(newConnectTask());}privatevoidsubmitRegisterTask(){Log.d(LOGTAG,"submitRegisterTask()...");submitConnectTask();addTask(newRegisterTask());}privatevoidsubmitLoginTask(){Log.d(LOGTAG,"submitLoginTask()...");submitRegisterTask();addTask(newLoginTask());}privatevoidaddTask(Runnablerunnable){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");}privatevoidremoveAccount(){Editoreditor=sharedPrefs.edit();editor.remove(Constants.XMPP_USERNAME);editor.remove(Constants.XMPP_PASSWORD);editor.commit();}/***Arunnabletasktoconnecttheserver.*/privateclassConnectTaskimplementsRunnable{finalXmppManagerxmppManager;privateConnectTask(){this.xmppManager=XmppManager.this;}publicvoidrun(){Log.i(LOGTAG,"ConnectTask.run()...");if(!xmppManager.isConnected()){//CreatetheconfigurationforthisnewconnectionConnectionConfigurationconnConfig=newConnectionConfiguration(xmppHost,xmppPort);//connConfig.setSecurityMode(SecurityMode.disabled);connConfig.setSecurityMode(SecurityMode.required);connConfig.setSASLAuthenticationEnabled(false);connConfig.setCompressionEnabled(false);XMPPConnectionconnection=newXMPPConnection(connConfig);xmppManager.setConnection(connection);try{//Connecttotheserverconnection.connect();Log.i(LOGTAG,"XMPPconnectedsuccessfully");//packetproviderProviderManager.getInstance().addIQProvider("notification","androidpn:iq:notification",newNotificationIQProvider());}catch(XMPPExceptione){Log.e(LOGTAG,"XMPPconnectionfailed",e);}xmppManager.runTask();}else{Log.i(LOGTAG,"XMPPconnectedalready");xmppManager.runTask();}}}/***Arunnabletasktoregisteranewuserontotheserver.*/privateclassRegisterTaskimplementsRunnable{finalXmppManagerxmppManager;privateRegisterTask(){xmppManager=XmppManager.this;}publicvoidrun(){Log.i(LOGTAG,"RegisterTask.run()...");if(!xmppManager.isRegistered()){finalStringnewUsername=newRandomUUID();finalStringnewPassword=newRandomUUID();Registrationregistration=newRegistration();PacketFilterpacketFilter=newAndFilter(newPacketIDFilter(registration.getPacketID()),newPacketTypeFilter(IQ.class));PacketListenerpacketListener=newPacketListener(){publicvoidprocessPacket(Packetpacket){Log.d("RegisterTask.PacketListener","processPacket().....");Log.d("RegisterTask.PacketListener","packet="+packet.toXML());if(packetinstanceofIQ){IQresponse=(IQ)packet;if(response.getType()==IQ.Type.ERROR){if(!response.getError().toString().contains("409")){Log.e(LOGTAG,"UnknownerrorwhileregisteringXMPPaccount!"+response.getError().getCondition());}}elseif(response.getType()==IQ.Type.RESULT){xmppManager.setUsername(newUsername);xmppManager.setPassword(newPassword);Log.d(LOGTAG,"username="+newUsername);Log.d(LOGTAG,"password="+newPassword);Editoreditor=sharedPrefs.edit();editor.putString(Constants.XMPP_USERNAME,newUsername);editor.putString(Constants.XMPP_PASSWORD,newPassword);editor.commit();Log.i(LOGTAG,"Accountregisteredsuccessfully");xmppManager.runTask();}}}};connection.addPacketListener(packetListener,packetFilter);registration.setType(IQ.Type.SET);//registration.setTo(xmppHost);//Map<String,String>attributes=newHashMap<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,"Accountregisteredalready");xmppManager.runTask();}}}/***Arunnabletasktologintotheserver.*/privateclassLoginTaskimplementsRunnable{finalXmppManagerxmppManager;privateLoginTask(){this.xmppManager=XmppManager.this;}publicvoidrun(){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,"Loggedninsuccessfully");//connectionlistenerif(xmppManager.getConnectionListener()!=null){xmppManager.getConnection().addConnectionListener(xmppManager.getConnectionListener());}//packetfilterPacketFilterpacketFilter=newPacketTypeFilter(NotificationIQ.class);//packetlistenerPacketListenerpacketListener=xmppManager.getNotificationPacketListener();connection.addPacketListener(packetListener,packetFilter);//判断是否处于连接状态(添加)if(!getConnection().isConnected()){xmppManager.runTask();}xmppManager.runTask();}catch(XMPPExceptione){Log.e(LOGTAG,"LoginTask.run()...xmpperror");Log.e(LOGTAG,"Failedtologintoxmppserver.Causedby:"+e.getMessage());StringINVALID_CREDENTIALS_ERROR_CODE="401";StringerrorMessage=e.getMessage();if(errorMessage!=null&&errorMessage.contains(INVALID_CREDENTIALS_ERROR_CODE)){xmppManager.reregisterAccount();return;}xmppManager.startReconnectionThread();}catch(Exceptione){Log.e(LOGTAG,"LoginTask.run()...othererror");Log.e(LOGTAG,"Failedtologintoxmppserver.Causedby:"+e.getMessage());xmppManager.startReconnectionThread();}//添加xmppManager.runTask();}else{Log.i(LOGTAG,"Loggedinalready");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)2010ModuadCo.,Ltd.**Thisprogramisfreesoftware;youcanredistributeitand/ormodify*itunderthetermsoftheGNUGeneralPublicLicenseaspublishedby*theFreeSoftwareFoundation;eitherversion2oftheLicense,or*(atyouroption)anylaterversion.**Thisprogramisdistributedinthehopethatitwillbeuseful,*butWITHOUTANYWARRANTY;withouteventheimpliedwarrantyof*MERCHANTABILITYorFITNESSFORAPARTICULARPURPOSE.Seethe*GNUGeneralPublicLicenseformoredetails.**YoushouldhavereceivedacopyoftheGNUGeneralPublicLicensealong*withthisprogram;ifnot,writetotheFreeSoftwareFoundation,Inc.,*51FranklinStreet,FifthFloor,Boston,MA02110-1301USA.*/packageorg.androidpn.server.console.controller;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importorg.androidpn.server.util.Config;importorg.androidpn.server.xmpp.push.NotificationManager;importorg.springframework.web.bind.ServletRequestUtils;importorg.springframework.web.servlet.ModelAndView;importorg.springframework.web.servlet.mvc.multiaction.MultiActionController;/***Acontrollerclasstoprocessthenotificationrelatedrequests.**@authorSehwanNoh(devnoh@gmail.com)*/publicclassNotificationControllerextendsMultiActionController{privateNotificationManagernotificationManager;publicNotificationController(){notificationManager=newNotificationManager();}publicModelAndViewlist(HttpServletRequestrequest,HttpServletResponseresponse)throwsException{ModelAndViewmav=newModelAndView();//mav.addObject("list",null);mav.setViewName("notification/form");returnmav;}publicModelAndViewsend(HttpServletRequestrequest,HttpServletResponseresponse)throwsException{Stringbroadcast=ServletRequestUtils.getStringParameter(request,"broadcast","Y");Stringusername=ServletRequestUtils.getStringParameter(request,"username");Stringtitle=ServletRequestUtils.getStringParameter(request,"title");Stringmessage=ServletRequestUtils.getStringParameter(request,"message");Stringuri=ServletRequestUtils.getStringParameter(request,"uri");StringapiKey=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);}ModelAndViewmav=newModelAndView();mav.setViewName("redirect:notification.do");returnmav;}}







参考博文:


真正解决了服务器重启客户端无法连接的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发布对应关系