个人备忘
拓展 : 七种服务器推送技术
(1)页面异步轮询
//java代码
package com.dongnaoedu.servlet3;
/**
* 获取随机字符串
* 创建日期:2017/09/21
* 创建时间: 22:50
*/
public class Const {
public static final String[] NEWS = {
"震惊!美国总统看到后都惊呆了!",
"整个X国X洲都慌了:X公司X亿收购了这家企业",
"震惊!男人看了会沉默,女人看了会流泪!不转不是中国人!",
"这几条人生定律,看后一生受益!【深度好文】","这位XX如今成长为XX巨鳄:曾被XX公司拒绝",
"X游戏十大最变态武器,第一名竟然是它!",
"一男子在XX买了一个XX,接下来不可思议的一幕发生了!",
"一小伙吃了XX,竟然当场死亡!盘点那些XXX的食物",
"XX动漫十大最强角色,第一名令人大跌眼镜!",
"XX电影禁播的秘密!XX年后终于解禁!",
"生活中致命的N大常识!",
"绝密视频流出,速看!",
"如今X国最缺的是什么?大学教授这么说!",
"XX不可告人的秘密:真相令所有人脸红心跳!",
"中国人打美国,暴爽!没WIFI也要看!不看不是中国人!",
"震惊!朴槿惠终生未嫁原来是心系一个中国男人!",
"震惊!六岁儿童公众场合口出狂言竟无人指责!中国的教育怎么了!",
"致富秘诀!它简直就是转运神器!我竟然才知道!",
"他来自山村,却成为北上广的精英,退休后守着一座海岛,和心爱的名媛终老",
"年轻貌美女孩抛弃7个备胎,最终与高富帅情定终生!",
"太可怕了!女子睡前在床上做了这件事,竟导致不孕不育!",
"震惊!著名LOL玩家和DOTA玩家互斥对方不算男人,现场数万人围观!"};
}
package com.dongnaoedu.servlet3;
import org.springframework.scheduling.annotation.Scheduled;
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 java.util.Random;
/**
* 后台controller
* 创建日期:2017/09/25
* 创建时间: 15:35
*/
@Controller
public class NewsController {
private DeferredResult<String> deferredResult ;
private Random r = new Random();
@RequestMapping("/news")
public String news(){
return "news";
}
@RequestMapping(value="/ontimeNews",produces = "text/html;charset=UTF-8")
@ResponseBody
public DeferredResult<String> ontimeNews(){
deferredResult = new DeferredResult<String>();
return deferredResult;
}
@Scheduled(fixedDelay = 5000)
public void refresh(){
if (deferredResult!=null){
int index = r.nextInt(Const.NEWS.length);
deferredResult.setResult(Const.NEWS[index]);
}
}
}
//前台ajax递归发送http请求即可。
function longPolling() {
var base = "${pageContext.request.contextPath}";
$.ajax({
url : base + "/ajax/toTask",
type : "GET",
datatype : "text",
data : "",
timeout: 50000,
error: function (XMLHttpRequest, textStatus, errorThrown) {
if (textStatus == "timeout") { // 请求超时
longPolling(); // 递归调用
// 其他错误,如网络错误等
} else {
return false ;
}
},
success: function (data) {
var i = 1 ;
var data1=eval(data.notices);
if(data1.length == 1 ){
for(key in data1){
$('#msg1').html(data1[key].t_notice_content) ;
$('#msg2').html(data1[key].t_notice_content) ;
$('#msg3').html(data1[key].t_notice_content) ;
}
}
if(data1.length == 2 ){
for(key in data1){
if(i == 1){
$('#msg1').html(data1[key].t_notice_content) ;
i = 2 ;
continue ;
}if(i == 2){
$('#msg2').html(data1[key].t_notice_content) ;
i = 1 ;
break ;
}
}
}
if(data1.length == 3){
for(key in data1){
if(i == 1){
$('#msg1').html(data1[key].t_notice_content) ;
i = 2 ;
continue ;
}if(i == 2){
$('#msg2').html(data1[key].t_notice_content) ;
i = 3 ;
continue ;
}else{
$('#msg3').html(data1[key].t_notice_content) ;
i = 1 ;
break ;
}
}
}
setTimeout("longPolling()",1000*30);
}
})
}
(2)页面Ajax长连接
应用同上,只是增加了客户端等待超时时间。
(3)see
流方式实现,比上面长连接好在,不关闭连接,其他基本一致
package com.dongnaoedu.sse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Random;
/**
* see
* 创建日期:2017/09/25
* 创建时间: 16:01
*/
@Controller
public class StockController {
@RequestMapping("/stock")
public String news(){
return "stock";
}
@RequestMapping(value="/stockOnTime",produces = "text/event-stream;charset=UTF-8")
@ResponseBody
public String push(){
Random r = new Random();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
StringBuilder sb = new StringBuilder("");
sb.append("retry:2000\n")
.append("data:")
.append((r.nextInt(100)+50)+",")
.append((r.nextInt(80)+45)+",")
.append((r.nextInt(60)+40)+",")
.append((r.nextInt(40)+35)+",")
.append("\n\n");
return sb.toString();
}
}
html
<%@ page language = "java" contentType= "text/html; charset=UTF-8" pageEncoding= "UTF-8" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>股票实时行情</title>
</head>
<body>
<h1>股票实时行情</h1>
<div>
<div>
<h2>股票列表</h2>
</div>
<div>
<h2 id="hint"></h2>
</div>
<hr>
<div>
<div><p>Java公司</p><p id="c0" style="color:#F00"></p><b><p id="s0">历史股价:</p></b></div>
<div><p>C/C++公司</p><p id="c1" style="color:#F00"></p><b><p id="s1">历史股价:</p></b></div>
<div><p>PHP公司</p><p id="c2" style="color:#F00"></p><b><p id="s2">历史股价:</p></b></div>
<div><p>Python公司</p><p id="c3" style="color:#F00"></p><b><p id="s3">历史股价:</p></b></div>
</div>
<hr>
</div>
<script type="text/javascript" src="assets/js/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
if (!!window.EventSource){
var source = new EventSource("stockOnTime");
source.onmessage=function (e) {
var dataObj = e.data;
console.log(dataObj);
var arr = dataObj.split(",");
$.each(arr,function (i,item) {
$("#c"+i).html("股价:"+item);
var s = $("#s"+i).html();
$("#s"+i).html(s+item+" ");
});
$("#hint").html("");
};
source.onopen=function (e) {
console.log("Conecting ....");
};
source.onerror=function () {
console.log("error ....");
};
}else{
$("#hint").html("Not support sse");
}
</script>
</body>
</html>
(4)webSocket + 定时器
//java代码
package com.znf4.controller.websocket;
import java.util.Map;
import javax.servlet.http.HttpSession;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
import com.znf4.platform.constants.CommonConst;
@Component
public class HandshakeInterceptor extends HttpSessionHandshakeInterceptor {
//拦截器 ,拦截动作
@Override
public boolean beforeHandshake(ServerHttpRequest request,
ServerHttpResponse response, WebSocketHandler wsHandler,
Map<String, Object> attributes) throws Exception {
System.out.println("Before Handshake");
if (request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
HttpSession session = servletRequest.getServletRequest().getSession(false);
if (session != null) {
//使用userName区分WebSocketHandler,以便定向发送消息
String userName = (String) session.getAttribute(CommonConst.CURRENT_USER);
attributes.put(CommonConst.CURRENT_USER,userName);
}
}
// 父类的实现方法 --》return super.beforeHandshake(request, response, wsHandler, attributes);
return true;
}
@Override
public void afterHandshake(ServerHttpRequest request,
ServerHttpResponse response, WebSocketHandler wsHandler,
Exception ex) {
System.out.println("After Handshake");
super.afterHandshake(request, response, wsHandler, ex);
}
}
package com.znf4.controller.websocket;
import java.io.IOException;
import java.util.ArrayList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import com.alibaba.fastjson.JSONObject;
import com.znf4.platform.constants.CommonConst;
import com.znf4.platform.notice.entity.Notice;
import com.znf4.platform.notice.enums.NoticeStatusEnum;
import com.znf4.platform.notice.server.NoticeServer;
/**
*
* @author agui
*/
@Component
public class SystemWebSocketHandler implements WebSocketHandler {
@Autowired
private NoticeServer noticeService;
private static final ArrayList<WebSocketSession> users; // 用来存储 登陆的用户
static {
users = new ArrayList<>();
}
@Bean
public SystemWebSocketHandler systemWebSocketHandler() {
return new SystemWebSocketHandler();
}
// 任何用户连接成功后,都会调用该方法,进行推送。
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
System.out.println("connect to the websocket success......");
users.add(session);
System.out.println("List 集合中共有 :" + users.size() + " 个 用户");
//String userName = (String) session.getAttributes().get(Constants.SESSION_USER);
//if (userName != null) {
System.out.println("用户不为空");
// 查询未读消息
//int count = 8;// webSocketService.getUnReadNews((String)
// session.getAttributes().get(Constants.WEBSOCKET_USERNAME));
Notice notice = new Notice() ;
notice.setStatus(NoticeStatusEnum.ACTIVE.getDesc());
notice = noticeService.queryOne(notice);
JSONObject json = new JSONObject() ;
json.put("msg1", notice.getContent()) ;
String result = json.toJSONString() ;
System.out.println("第一次链接获取到的 数据 :" + result);
session.sendMessage(new TextMessage(result));
}
//}
// 接收客户端输入的数据。。。
@Override
public void handleMessage(WebSocketSession wss, WebSocketMessage<?> wsm) throws Exception {
TextMessage returnMessage = new TextMessage(wsm.getPayload() + " received at server");
// 讲得到的数据返回给 发过来的客户端
wss.sendMessage(returnMessage);
// 给管理员发送消息
//systemWebSocketHandler().sendMessageToUser("18940982533" , new TextMessage(wsm.getPayload()+""));
//systemWebSocketHandler().sendMessageToUser("13998641323" , new TextMessage(wsm.getPayload()+""));
}
/**
* 消息传输过程中出现的异常处理函数
* 处理传输错误:处理由底层WebSocket消息传输过程中发生的异常
*/
@Override
public void handleTransportError(WebSocketSession wss, Throwable thrwbl) throws Exception {
if (wss.isOpen()) {
wss.close();
}
users.remove(wss);
System.out.println("websocket connection closed......");
}
/**
* websocket链接关闭的回调
* 连接关闭后:一般是回收资源等
*/
@Override
public void afterConnectionClosed(WebSocketSession wss, CloseStatus cs) throws Exception {
users.remove(wss);
System.out.println("websocket connection closed......");
}
// 处理拆分消息。如果发过来的消息过长,将会进行切割。
@Override
public boolean supportsPartialMessages() {
return false;
}
/**
* 给所有在线用户发送消息
*
* @param message
*/
public void sendMessageToUsers(TextMessage message) {
if (null != users) {
System.out.println("给所有人发小心 :由用户存在---");
for (WebSocketSession user : users) {
try {
if (user.isOpen()) {
user.sendMessage(message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
} else {
System.out.println("给所有人发小心 :没有用户存在");
}
}
/**
* 给某个用户发送消息
*
* @param userName
* @param message
*/
public void sendMessageToUser(String userName, TextMessage message) {
if (null != users) {
System.out.println("给某个人发小心:由用户存在---");
for (WebSocketSession user : users) {
if (user.getAttributes().get(CommonConst.CURRENT_USER).equals(userName)) {
try {
if (user.isOpen()) {
user.sendMessage(message);
}
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
} else {
System.out.println("给某个人发小心:没有用户存在");
}
}
}
package com.znf4.controller.websocket;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import org.springframework.context.annotation.Bean;
@Configuration
@EnableWebMvc
@EnableWebSocket
public class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {
public WebSocketConfig() {
}
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(systemWebSocketHandler(), "/websck").addInterceptors(new HandshakeInterceptor());
System.out.println("registed!");
registry.addHandler(systemWebSocketHandler(), "/sockjs/websck").addInterceptors(new HandshakeInterceptor())
.withSockJS();
}
@Bean
public WebSocketHandler systemWebSocketHandler() {
return new SystemWebSocketHandler();
}
}
//controller.java
package com.znf4.controller.notice;
import java.util.Random;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
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 org.springframework.web.context.request.async.DeferredResult;
import org.springframework.web.socket.TextMessage;
import com.alibaba.fastjson.JSONObject;
import com.znf4.controller.websocket.SystemWebSocketHandler;
import com.znf4.platform.notice.entity.Notice;
import com.znf4.platform.notice.enums.NoticeStatusEnum;
import com.znf4.platform.notice.server.NoticeServer;
/**
* 活动和公告
*/
@Controller
@RequestMapping("/merchant/notice")
public class NoticeController {
private static final Logger LOG = LoggerFactory.getLogger(NoticeController.class);
@Autowired
private NoticeServer noticeServer ;
@Bean
public SystemWebSocketHandler systemWebSocketHandler() {
return new SystemWebSocketHandler();
}
private static DeferredResult<String> deferredResult ; // 公告信息
/**
* 函数功能说明 : 获取一条公告推送
* 方式:短链接轮询
* @return
*/
@RequestMapping(value = "/queryNotice" , produces = "text/heml;charset=UTF-8")
@ResponseBody
public DeferredResult<String> queryNotice(){
System.out.println("开始");
deferredResult = new DeferredResult<String>() ;
System.out.println("输出");
return deferredResult ;
}
/**
* 定时推送
*/
// @Scheduled(fixedDelay = 5000 )
public void reFresh(){
LOG.info("开始循环");
if(deferredResult != null){
LOG.info("不为null");
Notice notice = new Notice() ;
notice.setStatus(NoticeStatusEnum.ACTIVE.getDesc());
/** 去数据库中查*/
noticeServer.queryOne(notice) ;
Random r = new Random() ;
deferredResult.setResult("这是一条公告 :" + r.nextInt()) ;
}
}
/**
* 函数功能说明 : 获取一条公告推送
* 方式:websocket 推送
* @return
*/
// @Scheduled(fixedDelay = 5000 )
public void socketNotice(){
System.out.println("定时器 调用 WebSocket 启动开始。。。。。。");
// 无关代码都省略了
// int unReadNewsCount = 9 ;
Notice notice = new Notice() ;
notice.setStatus(NoticeStatusEnum.ACTIVE.getDesc());
notice = noticeServer.queryOne(notice);
JSONObject json = new JSONObject() ;
json.put("msg1", notice.getContent()) ;
String result = json.toJSONString() ;
System.out.println("数据库获取到的给商人的公告 json :" + result);
// systemWebSocketHandler().sendMessageToUsers("13998641323", new
// TextMessage(jsonLn));
//systemWebSocketHandler().sendMessageToUser(username , new TextMessage(result));
systemWebSocketHandler().sendMessageToUsers(new TextMessage(result));
}
}
html
sockjs-0.3.min.js 必不可少
<script type="text/javascript">
window.onload = function connect() {
var path = '<%=basePath%>';
if ('WebSocket' in window) {
ws= new WebSocket("ws://" + path + "websck");
}
else if ('MozWebSocket' in window) {
ws = new MozWebSocket("ws://"+ path +"websck");
}
else {
ws = new SockJS("http://"+ path +"websck");
}
ws.onopen = function () {
};
ws.onmessage = function (event) {
var obj = eval('(' + event.data + ')');
$("#msg1").html(obj.msg1);
$("#msg2").html(obj.msg2);
$("#msg3").html(obj.msg3);
};
ws.onclose = function (event) {
};
}
</script>
pom.xml
<!-- tomcat websockt -->
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
<!--spring websocket库-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${org.springframework-version}</version>
</dependency>