基于websocket技术的网页弹幕实现

来源:互联网 发布:java是操作系统吗 编辑:程序博客网 时间:2024/05/18 00:59

前言:本弹幕是基于websocket技术实现的网页弹幕,需要HTML5技术支持。具备如下功能:
1、打开弹幕,从数据库里读取历史弹幕;
2、一个客户端发送弹幕,所有的客户端均可以看到。

具体实现:
网页端:

index.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%String path = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPE html><html>  <head>    <title>index.html</title>    <meta name="keywords" content="keyword1,keyword2,keyword3">    <meta name="description" content="this is my page">    <meta name="content-type" content="text/html; charset=UTF-8">    <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->      <style type="text/css">body {background: url(images/01.jpg); no-repeat top center;font-size: 12px;font-family: "微软雅黑";}* {margin: 0;padding: 0;}/* screen start*/.screen {width: 300px;height: 100px;background: #669900;}.dm {width: 100%;height: 100%;position: absolute;top: 0;left: 0;display: none;}.dm .d_screen .d_del {width: 38px;height: 38px;background: #600;display: block;text-align: center;line-height: 38px;text-decoration: none;font-size: 20px;color: #fff;border-radius: 19px;border: 1px solid #fff;z-index: 2;position: absolute;right: 20px;top: 20px;outline: none;}.dm .d_screen .d_del:hover {background: #F00;}.dm .d_screen .d_mask {width: 100%;height: 100%;background: #000;position: absolute;top: 0;left: 0;opacity: 0.6;filter: alpha(opacity = 60);z-index: 1;}.dm .d_screen .d_show {position: relative;z-index: 2;}.dm .d_screen .d_show div {font-size: 26px;line-height: 36px;font-weight: 500;position: absolute;top: 76px;left: 10;color: #fff;}/*end screen*//*send start*/.send {width: 100%;height: 76px;position: absolute;bottom: 0;left: 0;border: 1px solid red;}.send .s_filter {width: 100%;height: 76px;background: #000;position: absolute;bottom: 0;left: 0;opacity: 0.6;filter: alpha(opacity = 60);}.send  .s_con {width: 100%;height: 76px;position: absolute;top: 0;left: 0;z-index: 2;text-align: center;line-height: 76px;}.send .s_con .s_text {width: 800px;height: 36px;border: 0;border-radius: 6px 0 0 6px;outline: none;}.send .s_con .s_submit {width: 100px;height: 36px;border-radius: 0 6px 6px 0;outline: none;font-size: 14px;color: #fff;background: #65c33d;font-family: "微软雅黑";cursor: pointer;border: 1px solid #5bba32;}.send .s_con .s_submit:hover {background: #3eaf0e;}/*end send*/</style></head><body><form><a href="#" id="startDm">开启弹幕</a><!-- dm start --><div class="dm"><!-- d_screen start --><div class="d_screen"><a href="#" class="d_del">X</a><div class="d_mask"></div><div class="d_show"></div></div><!-- end d_screen --><!-- send start --><div class="send"><div class="s_filter"></div><div class="s_con"><input type="text" class="s_text" maxlength="30"/><input type="button"value="发表评论" class="s_submit" id="btn"/></div></div><!-- end send --></div><!-- end dm--></form><!-- <script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.0.js"></script> --><script src="js/jquery-1.11.1.min.js" type="text/javascript" charset="utf-8"></script><!-- <script type="text/javascript" src="websocket.js" id="websocket"> </script> --><script type="text/javascript">$(function() {    $("#startDm").click(function() {        $("#startDm,.dm").toggle(1000);        window.setTimeout(function(){          // reference to <head>          var head = document.getElementsByTagName('head')[0];          // a new CSS          /* var css = document.createElement('link');          css.type = "text/css";          css.rel = "stylesheet";          css.href = "new.css";   */        // a new JS          var js = document.createElement("script");          js.type = "text/javascript";          js.src = "websocket.js";          // preload JS and CSS          /* head.appendChild(css);   */        head.appendChild(js);          // preload image          /* new Image().src = "new.png";   */    },  1000) ;        /* window.setTimeout("document.getElementById('websocket').src='websocket +  js.js'" , 1000) ; */        /* var websocket=null;        var _top=80;        var index=0;        var host=window.location.host;        //判断当前浏览器是否支持WebSocket        if('WebSocket' in window){            websocket=new WebSocket("ws://192.168.50.155:8080/Danmu01/websocket");        }        else{            alert("Not Support WebSocket!");        }        //连接发生错误的回调方法        websocket.onerror = function(){            setMessageInnerHTML("error");        };        //连接成功建立的回调方法        websocket.onopen = function(){            setMessageInnerHTML("open");        }        //接收到消息的回调方法        websocket.onmessage = function(event){            setMessageInnerHTML(event);        }        //连接关闭的回调方法        websocket.onclose = function(){            setMessageInnerHTML("close");        }        //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。        window.onbeforeunload = function(){            websocket.close();        }        //将消息显示在网页上        function setMessageInnerHTML(innerHTML){            $(".d_show").append("<div id='"+index+"'>"+ innerHTML.data + "</div>");            launch();        }        //发送消息        function send(){         //var message = document.getElementById('text').value;            var message = $(".s_text").val();            alert(message);            websocket.send(message);        } */        //init_screen();    });    $(".d_del").click(function() {        $("#startDm,.dm").toggle(1000);        //init_screen();    });    $("#btn").click(function(){        send();    });    $(".s_text").keydown(function() {        var code = window.event.keyCode;        if (code == 13)//回车键按下时,输出到弹幕        {            send();        }    });});    /* $("#startDm").click(function() {        alert("forEach^^^") ;        <c:forEach var="danmu" items="${allDanmu}">                alert("进入forEach循环" + ${danmu.danmuInfo}) ;                $(".d_show").append("<div id='"+index+"'>"+ ${danmu.danmuInfo} + "</div>");        </c:forEach>    }) ; */function launch(){var _height = $(window).height();var _left = $(window).width() - $("#"+index).width();var time=10000;if(index%2==0)time=20000;_top+=80;if(_top>_height-100)_top=80;$("#"+index).css({left:_left,top:_top,color:getRandomColor()});$("#"+index).animate({left:"-"+_left+"px"},time,function(){});index++;}/* //初始化弹幕function init_screen() {var _top = 0;var _height = $(window).height();$(".d_show").find("div").show().each(function() {var _left = $(window).width() - $(this).width();var time=10000;if($(this).index()%2==0)time=20000; _top+=80;if(_top>_height-100)_top=80;$(this).css({left:_left,top:_top,color:getRandomColor()});$(this).animate({left:"-"+_left+"px"},time,function(){});});} *///随机获取颜色值function getRandomColor() {return '#' + (function(h) {return new Array(7 - h.length).join("0") + h})((Math.random() * 0x1000000 << 0).toString(16))}</script></body></html>

这一段jsp代码部分借鉴了潭州学院Array老师的弹幕页面,在此表示感谢。
通过研究上面一段代码可以发现,里面设置了websocket.js的定时加载并且加载了jquery-1.11.1.min.js。后一个.js文件可以在网上下到,只要把它放在对应的路径下就可以了。下面提供websocket.js的代码。

websocket.js

var websocket=null;var _top=80;var index=0;var host=window.location.host;//判断当前浏览器是否支持WebSocketif('WebSocket' in window){websocket=new WebSocket("ws://192.168.50.155:8080/Danmu01/websocket");/*("ws://"+host+"/Danmu/websocket");*/}else{alert("Not Support WebSocket!");}//连接发生错误的回调方法websocket.onerror = function(){    setMessageInnerHTML("error");};//连接成功建立的回调方法websocket.onopen = function(){    setMessageInnerHTML("open");}//接收到消息的回调方法websocket.onmessage = function(event){    setMessageInnerHTML(event);}//连接关闭的回调方法websocket.onclose = function(){    setMessageInnerHTML("close");}//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。window.onbeforeunload = function(){    websocket.close();}//将消息显示在网页上function setMessageInnerHTML(innerHTML){$(".d_show").append("<div id='"+index+"'>"+ innerHTML.data + "</div>");launch();}/*websocket.onmessage = function(msg) {    alert(msg.data);    setMessageInnerHTML(msg) ;};*///发送消息function send(){    //var message = document.getElementById('text').value;    var message = $(".s_text").val();    /*alert($(".s_text").val(""));    alert(message);*/    websocket.send(message);}

观察websocket.js,可知在开始的时候实例化了一个Websocket类,构造方法中传入的参数是”ws://192.168.50.155:8080/Danmu01/websocket”,代表项目所在服务器的ip地址+端口号+项目名+websocket,其中websocket对应服务端代码中@ServerEndpoint(“/websocket”)的websocket。

服务端代码:

package com.danmu.websocket;import java.io.IOException;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.concurrent.CopyOnWriteArraySet;import com.deyao.danmu.pojo.*;import javax.websocket.OnClose;import javax.websocket.OnError;import javax.websocket.OnMessage;import javax.websocket.OnOpen;import javax.websocket.Session;import javax.websocket.server.ServerEndpoint;import com.deyao.danmu.factory.ServiceFactory;@ServerEndpoint("/websocket")public class MyWebsocket {    private static CopyOnWriteArraySet<MyWebsocket> websocketPools=new CopyOnWriteArraySet<MyWebsocket>();    private Session session;    boolean index = false ;/*** 连接建立成功调用的方法* @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据*/    @OnOpen    public void onOpen(Session session) throws Exception{            this.session=session;            websocketPools.add(this);            index = true ;             onMessage("Welcome to DEYAO danmu ^_^" , this.session) ;    }/*** 连接关闭调用的方法*/    @OnClose    public void onClose(){            websocketPools.remove(this);    }/*** 收到客户端消息后调用的方法* @param message 客户端发送过来的消息* @param session 可选的参数*/    @OnMessage    public void onMessage(String message,Session session) throws Exception{        if (index) {                Map<String , Object> map = ServiceFactory.getIDanmuServiceInstance()                    .list(1, 1000, "", "userNickname") ;                List<Danmu> list = (List<Danmu>) map.get("allDanmu01") ;                for(int i = 0 ; i < list.size() ; i++) {                    String msg = list.get(i).getDanmuInfo() ;                    this.session.getBasicRemote().sendText(msg);                    System.out.println(msg);            }            index = false ;        } else {            Danmu danmu = new Danmu() ;            danmu.setDanmuInfo(message);            danmu.setUserId(null);            danmu.setUserNickname(null);            ServiceFactory.getIDanmuServiceInstance().insert(danmu);        }        for(MyWebsocket item:websocketPools) {            try {                item.send(message);            } catch (IOException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }           }    }    private void send(String message) throws IOException{        this.session.getAsyncRemote().sendText(message);        //this.session.getBasicRemote().sendText(message);    }/*** 发生错误时调用* @param session* @param error*/    @OnError    public void onError(Session session, Throwable error) {        System.out.println("发生错误");        error.printStackTrace();    }}

研究服务端代码,我们可以发现在初始的时候new了一个CopyOnWriteArraySet,通过的他的泛型可知他是保存websocket.js中新建的Websocket对象的。因为有一个客户端开始了弹幕就触发websocket.js中的onOpen方法,也就有了一个新的session,也就执行了服务端的onOpen方法,所以,在服务端的onOpen方法中,就要将新的session加入到CopyWriteArraySet中,并且在此时要读取数据库中的历史弹幕到前台。所以在onOpen中调用了onMessage方法,将数据库中的历史弹幕数据呈现到前台。这里要注意一点是读取历史弹幕数据的时候要使用this.session.getBasicRemote().sendText(msg);
onMessage方法是有新弹幕信息的时候自动调用的,这里在onOpen方法中调用他是为了让他读出历史弹幕信息。onMessage中的for循环就是用来将一个客户端发送的新消息推送到每一个session(即客户端)。

0 0
原创粉丝点击