服务器推送技术

个人备忘

拓展七种服务器推送技术

(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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值