SpringMVC 异步(长轮询)实现消息定点推送

Javascript代码 

 收藏代码

  1. $(function () {  
  2.       
  3.     getMsg();  
  4.   
  5.       
  6. });  
  7.   
  8. function getMsg()  
  9. {  
  10.     $.ajax({  
  11.         url:"/polling/msg",  
  12.         type:"get",  
  13.         data:{},  
  14.         success:function(data)  
  15.         {  
  16.             if(data != null && data!="")  
  17.                 alertShow(data.msg);  
  18.               
  19.             getMsg();  
  20.         }  
  21.     });  
  22. }   


 

Java代码 

 收藏代码

  1. /** 
  2.  *  
  3.  * @author {chensg}:2016年6月1日 
  4.  * example 
  5.  * 
  6.  */  
  7. @Controller  
  8. @RequestMapping("/polling/")  
  9. public class PollingController {  
  10.       
  11.     @Autowired  
  12.     MessageContainer messageContainer;  //全局存放每一个user创建的DeferredResult实例,key:userId,value:DeferredResult  
  13.     @Autowired  
  14.     RabbitTemplate rabbitTemplate;   
  15.     /** 
  16.      * 长轮询 
  17.      * @return 
  18.      */  
  19.     @RequestMapping(value="msg", method=RequestMethod.GET)  
  20.     public @ResponseBody DeferredResult getMessage() {  
  21.         final String userId = (UserDetails) SecurityContextHolder.getContext()  
  22.     .getAuthentication()  
  23.     .getPrincipal().getUsername();  
  24.         DeferredResult result = new DeferredResult(30000l,null);  //设置超时30s,超时返回null  
  25.         final Map resultMap=messageContainer.getUserMessages();  
  26.         resultMap.put(userId, result);    
  27.         result.onCompletion(new Runnable()   
  28.         {    
  29.             @Override    
  30.             public void run() {    
  31.                 resultMap.remove(userId);    
  32.             }    
  33.         });    
  34.           
  35.         return result;  
  36.     }  
  37.       
  38.     /** 
  39.      * test 新增需要推给某某用户的消息 
  40.      * @return 
  41.      */  
  42.     @RequestMapping(value="msg", method=RequestMethod.POST)  
  43.     public @ResponseBody RestResult addMessage(String msg,String userId) {  
  44.           
  45.         UserMessage userMsg = new UserMessage();  
  46.         userMsg.setUserId(userId);  
  47.         userMsg.setMsg(msg);  
  48.         //系统或者其他用户需要推送的消息放入消息队列  
  49.         rabbitTemplate.convertAndSend("test.exchange", "test.binding", userMsg);  
  50.           
  51.         return null;  
  52.     }  
  53. }  



页面加载完成时,该用户请求/polling/msg控制器接口,接口里会创建一个DeferredResult实例,设置超时30S,超时返回null。DeferredResult 允许应用程序从一个线程中返回,而何时返回则由线程决定。
SpringMVC 异步(长轮询)实现消息定点推送_第1张图片
消息实体类

Java代码 

 收藏代码

  1. public class UserMessage implements Serializable {  
  2.     /** 
  3.      *  
  4.      */  
  5.     private static final long serialVersionUID = 1L;   
  6.       
  7.     private String userId;  
  8.       
  9.     private String msg;  
  10.   
  11.     public String getUserId() {  
  12.         return userId;  
  13.     }  
  14.   
  15.     public void setUserId(String userId) {  
  16.         this.userId = userId;  
  17.     }  
  18.   
  19.     public String getMsg() {  
  20.         return msg;  
  21.     }  
  22.   
  23.     public void setMsg(String msg) {  
  24.         this.msg = msg;  
  25.     }  
  26.   
  27.       
  28. }  



配置rabbitMQ

Xml代码 

 收藏代码

  1.   
  2.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  3.     xmlns:rabbit="http://www.springframework.org/schema/rabbit"  
  4.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
  5.         http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit-1.5.xsd">  
  6.   
  7.       
  8.       
  9.     
  10.         host="${rabbitmq.host}" port="${rabbitmq.port}" username="${rabbitmq.username}" password="${rabbitmq.password}"  
  11.         virtual-host="/" />  
  12.       
  13.       
  14.     
  15.         retry-template="retryTemplate" />  
  16.       
  17.       
  18.       
  19.           
  20.           
  21.               
  22.               
  23.               
  24.           
  25.       
  26.       
  27.       
  28.       
  29.       
  30.       
  31.       
  32.       
  33.       
  34.           
  35.               
  36.           
  37.       
  38.       
  39.       
  40.     
  41.         class="com.xxx.controller.test.ServicePollingHandler" />  
  42.   
  43.       
  44.       
  45.         
  46.             method="testPollingHandle"  
  47.             queues="testQueue" />  
  48.       
  49.       
  50.   


 

Java代码 

 收藏代码

  1. public class ServicePollingHandler {  
  2.       
  3.     @Autowired  
  4.     MessageContainer messageContainer;  
  5.       
  6.     public void testPollingHandle(UserMessage userMessage)  
  7.     {  
  8.         Map msgContainer = messageContainer.getUserMessages();  
  9.         DeferredResult deferredResult = msgContainer.get(userMessage.getUserId());    
  10.   
  11.                 if (deferredResult!=null){    
  12.             deferredResult.setResult(userMessage);  //调用setResult(),线程返回信息。  
  13.         }    
  14.     }  
  15. }  

 

Java代码 

 收藏代码

  1. @PropertySource(value="classpath:application.properties")  
  2. @ImportResource({"classpath:amqp.xml"})  
  3. public class RootConfig {  
  4.   
  5.     @Bean  
  6.     public MessageContainer messageContainer() {  
  7.         return new MessageContainer();  
  8.     }  
  9.       
  10. }  



 

Java代码 

 收藏代码

  1. public class MessageContainer {  
  2.   
  3.     private ConcurrentHashMap userMessages = new ConcurrentHashMap();   //线程安全  
  4.   
  5.     public ConcurrentHashMap getUserMessages() {  
  6.         return userMessages;  
  7.     }  
  8.       
  9. }  



该例子的用途,当一个用户登录页面时,异步请求后台/polling/msg,后台创建一个线程,维持改长连接30s,当超时或者返回信息,页面则再次请求后台,维持一个30s的长连接(长轮询)。
系统或者其他用户调用/polling/msg  method:post,传入msg与userId,控制器把消息放入消息队列,消息队列把消息推送到ServicePollingHandler类testPollingHandle()方法,该方法根据userId获得该用户登陆之后的页面长轮询创建的deferredResult实例,调用setResult,页面接受到线程返回消息。

可以基于以上代码,实现web聊天

本文来源于:https://chenshangge.iteye.com/blog/2302710 如有不当请告知删除

你可能感兴趣的:(SpringMVC 异步(长轮询)实现消息定点推送)