SpringMVC asynchronous (long polling) to achieve message push

$(function () {
	
	getMsg();

	
});

function getMsg()
{
	$.ajax({
		url:"/polling/msg",
		type:"get",
		data:{},
		success:function(data)
		{
			if(data != null && data!="")
				alertShow(data.msg);
			
			getMsg();
		}
	});
}



/**
 *
 * @author {chensg}: June 1, 2016
 * example
 *
 */
@Controller
@RequestMapping("/polling/")
public class PollingController {
	
	@Autowired
	MessageContainer messageContainer; //Globally store the DeferredResult instance created by each user, key: userId, value: DeferredResult
	@Autowired
	RabbitTemplate rabbitTemplate;
	/**
	 * long polling
	 * @return
	 */
	@RequestMapping(value="msg", method=RequestMethod.GET)
	public @ResponseBody DeferredResult<UserMessage> getMessage() {
		final String userId = (UserDetails) SecurityContextHolder.getContext()
    .getAuthentication()
    .getPrincipal().getUsername();
		DeferredResult<UserMessage> result = new DeferredResult<UserMessage>(30000l,null); //Set the timeout to 30s, the timeout returns null
	    final Map<String, DeferredResult> resultMap=messageContainer.getUserMessages();
	    resultMap.put(userId, result);  
	    result.onCompletion(new Runnable()
	    {  
	    	@Override  
            public void run() {  
                resultMap.remove(userId);  
            }  
        });  
	    
	    return result;
	}
	
	/**
	 * test Add a message that needs to be pushed to a certain user
	 * @return
	 */
	@RequestMapping(value="msg", method=RequestMethod.POST)
	public @ResponseBody RestResult addMessage(String msg,String userId) {
		
		UserMessage userMsg = new UserMessage();
		userMsg.setUserId(userId);
		userMsg.setMsg(msg);
		//The message that the system or other users need to push is put into the message queue
		rabbitTemplate.convertAndSend("test.exchange", "test.binding", userMsg);
		
		return null;
	}
}


When the page is loaded, the user requests the /polling/msg controller interface, a DeferredResult instance will be created in the interface, the timeout is set to 30S, and the timeout returns null. DeferredResult<?> allows the application to return from a thread, and when to return is up to the thread.

message entity class
public class UserMessage implements Serializable {
	/**
	 *
	 */
	private static final long serialVersionUID = 1L;
	
	private String userId;
	
	private String msg;

	public String getUserId() {
		return userId;
	}

	public void setUserId(String userId) {
		this.userId = userId;
	}

	public String getMsg() {
		return msg;
	}

	public void setMsg(String msg) {
		this.msg = msg;
	}

	
}


Configure rabbitMQ
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:rabbit="http://www.springframework.org/schema/rabbit"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit-1.5.xsd">

	
	<!-- Create a connectionFactory -->
	<rabbit:connection-factory id="rabbitConnectionFactory"
		host="${rabbitmq.host}" port="${rabbitmq.port}" username="${rabbitmq.username}" password="${rabbitmq.password}"
		virtual-host="/" />
	
	<!-- Create a rabbitTemplate, set retryTemplate -->
	<rabbit:template id="rabbitTemplate" connection-factory="rabbitConnectionFactory"
		retry-template="retryTemplate" />
	
	<!-- Create a retryTemplate -->
	<bean id="retryTemplate" class="org.springframework.retry.support.RetryTemplate">
		<property name="backOffPolicy">
		<bean class="org.springframework.retry.backoff.ExponentialBackOffPolicy">
			<property name="initialInterval" value="500" />
			<property name="multiplier" value="10.0" />
			<property name="maxInterval" value="10000" />
		</bean>
	</property>
	</bean>
	
	<rabbit:admin connection-factory="rabbitConnectionFactory" />
	
	<!-- Create a queue for message push-->
	<rabbit:queue id="testQueue" name="test.polling" />
	
	<rabbit:direct-exchange name="test.exchange">
		<rabbit:bindings>
			<rabbit:binding queue="test.polling" key="test.binding" />
		</rabbit:bindings>
	</rabbit:direct-exchange>
	
	<!-- Create a message handler -->
	<bean id="servicePollingHandler"
		class="com.xxx.controller.test.ServicePollingHandler" />

	<!-- Bind listeners and queues-->
	<rabbit:listener-container connection-factory="rabbitConnectionFactory">
		<rabbit:listener ref="servicePollingHandler"
			method="testPollingHandle"
			queues="testQueue" />
	</rabbit:listener-container>
	
</beans>



public class ServicePollingHandler {
	
	@Autowired
	MessageContainer messageContainer;
	
	public void testPollingHandle(UserMessage userMessage)
	{
		Map<String, DeferredResult> msgContainer = messageContainer.getUserMessages();
		DeferredResult<UserMessage> deferredResult = msgContainer.get(userMessage.getUserId());  

	    	    if (deferredResult!=null){  
	        deferredResult.setResult(userMessage); //Call setResult(), the thread returns information.
	    }  
	}
}


@PropertySource(value="classpath:application.properties")
@ImportResource({"classpath:amqp.xml"})
public class RootConfig {

	@Bean
	public MessageContainer messageContainer() {
		return new MessageContainer();
	}
	
}




public class MessageContainer {

	private ConcurrentHashMap<String, DeferredResult> userMessages = new ConcurrentHashMap<String, DeferredResult>();	//线程安全

	public ConcurrentHashMap<String, DeferredResult> getUserMessages() {
		return userMessages;
	}
	
}



The purpose of this example is that when a user logs in to the page, the background /polling/msg is asynchronously requested, a thread is created in the background, and the connection is extended for 30s. When the timeout or information is returned, the page requests the background again and maintains a long connection for 30s ( long polling).
The system or other users call /polling/msg method:post, pass in msg and userId, the controller puts the message into the message queue, and the message queue pushes the message to the testPollingHandle() method of the ServicePollingHandler class, which obtains the user after logging in according to the userId. The deferredResult instance created by the page long polling, call setResult, and the page receives the thread return message.

Web chat can be implemented based on the above code

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326861150&siteId=291194637