Spring Boot使用EventSource和觀察者模式實現服務端推送

服務端:

Controller:

package com.example.demo;

import java.io.IOException;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.async.DeferredResult;

import com.example.demo.service.MsgService;


@Controller
@RequestMapping("/")
public class MsgControl {
	
	@Resource(name="msgService")
	private MsgService msgService;
	
	@ResponseBody
	@RequestMapping(value = "/getMsg", produces="text/event-stream;charset=UTF-8")
	DeferredResult<String> getMsg(HttpServletResponse response) throws IOException {
		response.setContentType("text/event-stream");
    	response.setCharacterEncoding("UTF-8");
    	response.setStatus(200);
    	msgService.removeErrorResponse();
    	msgService.getListRes().add(response);
    	if(!response.getWriter().checkError()){
    		response.getWriter().write("data:hello\n\n");
    		response.getWriter().flush();
    	}
    	DeferredResult<String> df = new DeferredResult<String>(60000l);
    	return df;
    }
}

Service:

package com.example.demo.service;

import java.io.PrintWriter;
import java.util.Iterator;
import java.util.Vector;
import java.util.Random;
import javax.servlet.http.HttpServletResponse;

import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

@Lazy(value = false)
@EnableScheduling
@Service(value="msgService")
public class MsgService {
	
	final Vector<HttpServletResponse> list_res= new Vector<HttpServletResponse>();
	
	public Vector<HttpServletResponse> getListRes()
	{
		return list_res;
	}
	
	@Scheduled(initialDelay = 0, fixedDelay = 3*1000)
	public void run() {
		this.removeErrorResponse();
		Iterator<HttpServletResponse> it = list_res.iterator();
		Random rand =new Random();
		int num=rand.nextInt(100);
		while(it.hasNext())
		{
			PrintWriter pw = null;
			try {
				pw = it.next().getWriter();
				if(pw == null || pw.checkError())
				{				
					continue;
				}
	    		pw.write("data:msg: hello, the random num is: " + num + "\n\n");
	    		pw.flush();
			} catch (Exception e) {
				
			} 
		}
	}
	
	public synchronized void removeErrorResponse(){
		Iterator<HttpServletResponse> it = list_res.iterator();
		while(it.hasNext())
		{
			PrintWriter pw = null;
			try {
				pw = it.next().getWriter();
				if(pw == null)
				{
					it.remove();
					continue;
				}
				else if(pw.checkError()){
					pw.close();
					it.remove();
					continue;
				}
			} catch (Exception e) {				
				it.remove();
			} 	
		}
	}
}

前端代碼:

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>信息</title>
</head>
<body>
	<div id='msg'>
</div>
<script>
	if (typeof(EventSource) !== "undefined") {
		var eventSource = new EventSource("/getMsg");
		
		eventSource.onmessage = function (event) {
			document.getElementById("msg").innerHTML = event.data;
			  
		}	        
		eventSource.addEventListener('error', function (event) {
			console.log("錯誤:" + event);
		});
		eventSource.addEventListener('open', function (event) {
			console.log("建立連接:" + event);
		});
	}
	else {
		document.getElementById("msg").innerHTML = "抱歉,您的瀏覽器不支持 server-sent 事件 ...";
	}   
</script>
</body>
</html>

運行結果:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章