1,服务端推送技术
- 基本原理:当客户端向服务端发送请求时,服务端会抓住这个请求不放,等有数据更新时,再返回给客户端,当客户端接收消息后,再向服务端发送请求,周而复始。
1,创建WebInitializer类和MyMvcConfig类
package com.zyf.config;
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;
/**
* Created by zyf on 2018/3/6.
*/
public class WebInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(MyMvcConfig.class);
context.setServletContext(servletContext);
context.refresh();
ServletRegistration.Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(context));
servlet.addMapping("/");
servlet.setLoadOnStartup(1);
}
}
package com.zyf.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
/**
* Created by zyf on 2018/3/6.
*/
@Configuration
@EnableWebMvc
@ComponentScan("com.zyf")
public class MyMvcConfig extends WebMvcConfigurerAdapter {
@Bean
public InternalResourceViewResolver viewResolver(){
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/classes/views");
viewResolver.setSuffix(".jsp");
viewResolver.setViewClass(JstlView.class);
return viewResolver;
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/sse").setViewName("/sse");
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/assets/**").addResourceLocations("classpath:/assets/");
}
}
2,创建SseController
package com.zyf.controller;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Random;
/**
* Created by zyf on 2018/3/6.
*/
@Controller
public class SseController {
/**
* 若使用SSE,则需要向服务器端输出的类型为:text/event-stream
*
* @return
*/
@RequestMapping(value = "/push",produces = {"text/event-stream;charset=UTF-8"})
@ResponseBody
public String push(){
Random r = new Random();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "data:SSE 1,2,3 " + r.nextInt() + "\n\n";
}
}
3,创建sse.jsp演示文件
<%--
Created by IntelliJ IDEA.
User: zyf
Date: 2018/3/6
Time: 上午12:52
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>SSE Demo</title>
<script type="text/javascript" src="../assets/js/jquery-3.2.1.min.js"></script>
</head>
<body>
<div id="msgFromPush">
</div>
<script type="text/javascript">
if(!!window.EventSource){//该对象,只有新式浏览器才有,该对象就是SSE的客户端
var source = new EventSource('push');
s = '';
//添加监听获取服务器传递过来的消息
source.addEventListener('message',function (e) {
s+=e.data+"<br/>";
$("#msgFromPush").html(s);
})
source.addEventListener('open',function (e) {
console.log("连接打开.");
},false);
source.addEventListener('error',function (e) {
if(e.readyState == EventSource.CLOSED){
console.log("连接关闭");
}else {
console.log(e.readyState);
}
},false)
}else {
console.log("sorry,你的浏览器有点旧");
}
</script>
</body>
</html>
4,部署运行演示
2,Servlet 3.0+异步方法处理
1,在WebInitialiazer中开启异步方法支持
public class WebInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
....
//开启异步支持
servlet.setAsyncSupported(true);
}
}
2,在MyMvcConfig开启对异步任务的支持
package com.zyf.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
/**
* Created by zyf on 2018/3/6.
*/
@Configuration
@EnableWebMvc
@EnableScheduling//开启对异步执行的支持
@ComponentScan("com.zyf")
public class MyMvcConfig extends WebMvcConfigurerAdapter {
....
}
3,创建PushService
package com.zyf.service;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.async.DeferredResult;
/**
* Created by zyf on 2018/3/6.
*/
@Service
public class PushService {
/**
* 在PushService生成DeferredResult给控制器使用
*/
private DeferredResult<String> deferredResult;
public DeferredResult<String> getAsyncUpdate() {
deferredResult = new DeferredResult<>();
return deferredResult;
}
/**
* 通过该注解定时更新DeferredResult
*/
@Scheduled(fixedDelay = 3000)
public void refresh(){
if(deferredResult != null){
deferredResult.setResult(Long.toString(System.currentTimeMillis()));
}
}
}
4,创建控制器
package com.zyf.controller;
import com.zyf.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;
/**
* Created by zyf on 2018/3/6.
*/
@Controller
public class AsyncController {
/**
* 自动装配
*/
@Autowired
PushService pushService;
@RequestMapping("/defer")
@ResponseBody
public DeferredResult<String> deferredCall(){
//返回给客户端
return pushService.getAsyncUpdate();
}
}
5,创建展示页面async.jsp
<%--
Created by IntelliJ IDEA.
User: zyf
Date: 2018/3/6
Time: 上午1:29
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>servlet async support</title>
<script type="text/javascript" src="../assets/js/jquery-3.2.1.min.js"></script>
</head>
<body>
<h1 id="result"></h1>
<script type="text/javascript">
deferred();
function deferred() {
$.get('defer',function (data) {
$('#result').html(data);
deferred();
});
}
</script>
</body>
</html>
6,添加ViewController
registry.addViewController("/async").setViewName("/async");