SSE即 server send event 服务器发送事件,在在早期可能会使用ajax向服务器轮询的方式,使浏览器第一时间接受到服务器的消息,但这种频率不好控制,消耗也比较大。
但是对于SSE来说,当客户端向服务端发送请求,服务端会抓住这个请求不放,等到有数据时才返回给客户端,但客户端手动消息后,再向服务器发送请求,周而复始。这种方式好处是减少了服务器的请求数量,也大大减少了服务器的压力。
以下是第一种方式的代码的演示,浏览器不断向服务器请求,服务器用线程睡眠5s再返回结果。
1、SseController 控制器
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Random;
/**
* @description: 服务器端推送控制器
*
* @author: Shenshuaihu
* @version: 1.0
* @data: 2019-06-25 23:29
*/
@Controller
public class SseController {
/**
* 输出类型 text/event-stream 是对服务器端SSE的支持
* 此处每5s向浏览器推送随机消息
* @return
*/
@RequestMapping(value = "/push", produces = "text/event-stream")
public @ResponseBody String push() {
Random random = new Random();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "data:Testing 1,2,3: " + random.nextInt() + "\n\n";
}
}
2、显示结果的页面 sse.jsp
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
SSE-Code
sse.jsp
服务器推送 可以用于消息订阅
解决长短轮询不是解决问题
server send event 当客户端方服务器发送请求时 服务器抓住不放 等有数据时 再回复给客户端,客户端收到消息时发给送给服务器,如此循环
参考内容:
https://www.jianshu.com/p/bc5a9b4a1cd1
显示的结果
SSE-.png
二、使用Servlet 3.0 + 异步方法处理,第二种方式演示,浏览器循环请求服务端,服务端用定时任务,每5S设置一下数据,返回给浏览器
1、开启异步方法的支持 WebInitializer.java
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration.Dynamic;
/**
* @description: Web配置 代替web.xml
* @author: Shenshuaihu
* @version: 1.0
* @data: 2019-06-13 23:22
*/
public class WebInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(MyMvcConfig.class);
// 新建的webApplicationContext ,注册配置类,并将其和当前servletContext关联。
context.setServletContext(servletContext);
// 注册SpringMVC 的 DispatcherServlet
Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(context));
servlet.addMapping("/");
servlet.setLoadOnStartup(1);
// 开启对异步的支持
servlet.setAsyncSupported(true);
}
}
2、AsyncController.java 控制层,只用掉service
import com.ch4.service.PushService;
import org.springframework.beans.factory.annotation.Autowired;
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;
/**
* @description:
*
* @author: Shenshuaihu
* @version: 1.0
* @data: 2019-06-27 08:32
*/
@Controller
public class AsyncController {
@Autowired
private PushService pushService;
@RequestMapping("/defer")
@ResponseBody
public DeferredResult deferredCall() {
return pushService.getAsyncUpdate();
}
}
3、PushService.java
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.async.DeferredResult;
/**
* @description: SSE 定时任务
* 在PushService里面产生 DeferredResult 给控制器使用,
* 通过 @Scheduled 定时更新DeferredResult
*
* @author: Shenshuaihu
* @version: 1.0
* @data: 2019-06-27 08:32
*/
@Service
public class PushService {
private DeferredResult deferredResult;
public DeferredResult getAsyncUpdate() {
deferredResult = new DeferredResult();
return deferredResult;
}
@Scheduled(fixedDelay = 5000)
public void refresh() {
if (deferredResult != null) {
deferredResult.setResult(new Long(System.currentTimeMillis()).toString());
}
}
}
3、数据页面async.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
async support-Code
defer.jsp
4、需要在核销配置类用开启任务
@Configuration
@EnableWebMvc
@ComponentScan("com.ch4")
@EnableScheduling
public class MyMvcConfig extends WebMvcConfigurerAdapter {}
SSE-aync.png
总结:
SSE用于订阅消息,是需要浏览器不断的请求,与websocket有相似之处
2019/06/30晚于成都