Websocket相遇、相知、相爱、相杀(附源码和在线演示)

本人博客全部迁至个人博客,柒情博客http://www.ityw.club ,后续所有博客将在柒情博客上进行更新。

一、相遇

某天发现某个网站有可以检测IP的功能,能检测出IP是否高匿、延时、地区,恰好前不久做了能提取IP的项目,正好可以利用这个接口提高我们使用IP的质量,咋办呢?

打开我们的Fiddler盘它!

fd:努力工作中!

我:啥? 没数据 没数据  fd坏了? 打开浏览器调试一波

浏览器:努力工作中!

我:啥? 还是没数据? 今天见鬼了?

让我郁闷了好久,平时所向无敌的FD大法失效了,本来还以为是那个网站随机返回的假数据,于是机智的我看了下源码,嘿嘿嘿,总算让我抓住了今天我们的主角 “webSocket”,原来那个网站在进页面的时候就直接用webSocket和服务器建立了长连接,所以我们就抓不到包啦,主角找出来了 大结局吧! 不不不 害我郁闷这么久 继续盘它。

二、相知

于是开始疯狂百度谷歌中,终于发现了一篇通俗易懂有意思的文章,也发现了一位发型很有型的实战大佬。

想和webSocket相知的 进去和webSocket交流下感情吧,通道如下:

有趣的灵魂大佬:https://www.zhihu.com/question/20215561

实战大佬:https://www.cnblogs.com/xdp-gacl/p/5193279.html

三、相爱

简单的和webSocket交流了下感情,发现webSocket还是挺有魅力的,于是我决定继续盘它,毕竟滴水之恩须涌泉相报嘛。

下面我们开始用webSocket做个小小的聊天室吧,来上我们的祖传代码!

1.项目结构图

2.在pom.xml中引入我们的jar包

<dependency>
    <groupId>javax</groupId>
    <artifactId>javaee-api</artifactId>
    <version>8.0</version>
    <scope>provided</scope>
</dependency>

3.后端代码

/**
 * @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,
 * 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
 */
@ServerEndpoint("/websocket")
public class WebSocket {
    //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;

    //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
    private static CopyOnWriteArraySet<WebSocket> webSocketSet = new CopyOnWriteArraySet<WebSocket>();

    //与某个客户端的连接会话,需要通过它来给客户端发送数据
    private Session session;

    /**
     * 连接建立成功调用的方法
     * @param session  可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
     */
    @OnOpen
    public void onOpen(Session session){
        this.session = session;
        webSocketSet.add(this);     //加入set中
        addOnlineCount();           //在线数加1
        //更新页面在线人数
        for(WebSocket item: webSocketSet){
            try {
                item.sendMessage(String.valueOf(getOnlineCount()));
            } catch (IOException e) {
                e.printStackTrace();
                continue;
            }
        }
        System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(){
        webSocketSet.remove(this);  //从set中删除
        subOnlineCount();           //在线数减1
        //更新页面在线人数
        for(WebSocket item: webSocketSet){
            try {
                item.sendMessage(String.valueOf(getOnlineCount()));
            } catch (IOException e) {
                e.printStackTrace();
                continue;
            }
        }
        System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     * @param message 客户端发送过来的消息
     * @param session 可选的参数
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("来自客户端的消息:" + message);
        //群发消息
        for(WebSocket item: webSocketSet){
            try {
                item.sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
                continue;
            }
        }
    }

    /**
     * 发生错误时调用
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error){
        System.out.println("发生错误");
        error.printStackTrace();
    }

    /**
     * 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。
     * @param message
     * @throws IOException
     */
    public void sendMessage(String message) throws IOException{
        this.session.getBasicRemote().sendText(message);
        //this.session.getAsyncRemote().sendText(message);
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocket.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocket.onlineCount--;
    }
}

4.前端代码

<%@ page language="java" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
    <title>柒情</title>
    <script src="static/base/jquery.min.js" charset="utf-8"></script>
    <link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,600" rel="stylesheet">
    <link rel="stylesheet" href="static/socket/css/reset.min.css">
    <link rel="stylesheet" href="static/socket/css/style.css">
    <link rel="stylesheet" href="static/layui/css/layui.css" media="all">
    <script type="text/javascript" src="static/layui/layui.all.js"></script>
    <script  src="static/socket/js/index.js"></script>
    <style type="text/css">
        .msg-text-color{
            color:#8097C2;
            margin-bottom:5px;
        }
        .msg-text-margin{
            margin-top: 13%;
        }
        .msg-text-me-margin{
            margin-top: 10%;
            margin-left:59%;
        }
    </style>
</head>
<body>
<div class="wrapper">
    <div class="container">
        <div class="left">
            <div class="top">
                <input type="text" placeholder="Search" />
                <a href="javascript:;" class="search"></a>
            </div>
            <ul class="people">
                <li class="person" data-chat="person6">
                    <img src="static/socket/img/drake.jpg" alt="" />
                    <span class="name">Drake</span>
                    <span class="time">2:09 PM</span>
                    <span class="preview">howdoyoudoaspace</span>
                </li>
            </ul>
        </div>
        <div class="right">
            <div class="top"><span>To: <span class="name" id="menNum">Dog Woofson</span></span></div>
            <div class="chat" data-chat="person2" id="message" style="height:78%;overflow:auto">
                <div class="conversation-start">
                    <span>hi, 柒情</span>
                </div>
            </div>

            <div class="write">
                <a href="javascript:;" class="write-link attach"></a>
                <input type="text" id="text"/>
                <a href="javascript:;" class="write-link smiley"></a>
                <a href="javascript:;" class="write-link send" onclick="send()"></a>
            </div>
        </div>
    </div>
</div>
</body>

<script type="text/javascript">
    var websocket = null;
    var intervaler = null;
    //判断当前浏览器是否支持WebSocket
    if ('WebSocket' in window) {
        //这里需要改成自己项目的地址
        websocket = new WebSocket("ws://www.lingchang.club/websocket");
        getName();
        //历史消息
        var storage=window.localStorage;
        for(var i=0;i<storage.length;i++){
            var key=storage.key(i);
            var value=storage.getItem(key);
            if(value.indexOf("{")>-1){
                var obj = JSON.parse(value);
                if(null!=key&&key.indexOf("bubble")>-1){
                    if(key.indexOf("You")>-1){
                        setMessageInnerHTML(obj,"bubble you");
                    }else{
                        setMessageInnerHTML(obj,"bubble me");
                    }
                }
            }
        }
        lastBomScrollBar();
    }
    else {
        alert('当前浏览器 Not support websocket')
    }

    function creatData(name,time,msg) {
        var data=new Object();
        data.name=name;
        data.time=time;
        data.msg=msg;
        return data;
    }

    function lastBomScrollBar() {
        //滚动条定位在最下面
        $('.chat').scrollTop($('.chat')[0].scrollHeight);
    }


    //连接发生错误的回调方法
    websocket.onerror = function () {
        console.log("WebSocket连接发生错误");
    };

    //连接成功建立的回调方法
    websocket.onopen = function (event) {
        console.log("WebSocket连接成功");
    }

    //接收到消息的回调方法
    websocket.onmessage = function (event) {
        if(event.data.indexOf("{")>-1){
        var dt = JSON.parse(event.data);
        var storage=window.localStorage;
        var name=storage.getItem("ltName");
        if(""==name||null==name||name=="undfined"){
            return false;
        }
        //这里是根据聊天者的名字区分是否为发送者的,假如两人名字一样会有bug,需要正式使用的话建议名字用用户的输入的名称和时间戳拼接
        if(name==dt.name){
        storage.setItem(dt.time +"-bubbleMe",event.data);
        setMessageInnerHTML(dt,"bubble me");
        }else{
        storage.setItem(dt.time +"-bubbleYou",event.data);
        setMessageInnerHTML(dt,"bubble you");
        var msg='【您有新的消息】';
        showTips(msg);
        }
        }else{
            $("#menNum").html("当前在线人数:"+event.data+"人");
        }
    }

    //连接关闭的回调方法
    websocket.onclose = function () {
        console.log("WebSocket连接关闭");
    }

    //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
    window.onbeforeunload = function () {
        closeWebSocket();
    }
    //获取发送人的名字
    function getName(){
        var storage=window.localStorage;
        var name=storage.getItem("ltName");
        if(""==name||null==name||name=="undfined"){
            //prompt层
            layer.prompt({title: '输入昵称,并确认', formType: 2,offset: 'auto'}, function(pass, index){
                layer.close(index);
                if(null==pass||""==pass){
                    layer.msg('昵称不能为空鸭,重新输入吧。');
                    getName();
                    return false;
                }
                var storage=window.localStorage;
                storage.setItem("ltName",pass);
                name=pass;
            });
        }
        return name;
    }

    //将消息显示在网页上
    function setMessageInnerHTML(data,clas) {
        if(clas.indexOf("you")>-1){
            var msg="<div class='msg-text-color msg-text-margin'> "+data.name+" "+ format(data.time)+" </div> <div class='"+clas+"'> "+data.msg+" </div>";
            document.getElementById('message').innerHTML += msg + '<br/>';
            lastBomScrollBar();
        }else{
            var msg="<div class='msg-text-color msg-text-me-margin'> "+format(data.time)+" "+ data.name+" </div> <div class='"+clas+"'> "+data.msg+" </div>";
            document.getElementById('message').innerHTML += msg + '<br/>';
            lastBomScrollBar();
        }
    }

    //关闭WebSocket连接
    function closeWebSocket() {
        websocket.close();
    }

    //发送消息
    function send() {
        var message = document.getElementById('text').value;
        var storage=window.localStorage;
        var name=storage.getItem("ltName");
        var data=creatData(name,(new Date()).getTime(),message);
        websocket.send(JSON.stringify(data));
        $("#text").val("");
    }
    //回车发送
    document.onkeydown = function (e) {
        if (!e) e = window.event;
        if ((e.keyCode || e.which) == 13) {
            send();
        }
    }

    function add0(m){return m<10?'0'+m:m }
    //时间戳转换为时间类型
    function format(shijianchuo)
    {
        var time = new Date(shijianchuo);
        var y = time.getFullYear();
        var m = time.getMonth()+1;
        var d = time.getDate();
        var h = time.getHours();
        var mm = time.getMinutes();
        var s = time.getSeconds();
        return y+'-'+add0(m)+'-'+add0(d)+' '+add0(h)+':'+add0(mm)+':'+add0(s);
    }
    //进入页面关闭消息提示
    document.addEventListener('visibilitychange', function() {
        var isHidden = document.hidden;
        if (!isHidden) {
            clearInterval(intervaler);
            showTips("柒情");
            intervaler = null;
        }
    });

    //有消息浏览器标签处提示
    function showTips(tip){
        intervaler = setInterval(function(){
            if(document.title === tip&&"柒情"!=document.title){
                document.title = '【      】';
            }else{
                document.title = tip;
            }
        },300);
    }

</script>
</html>

四、相杀

啥? 你还想看戏? no no no,接下来就是你们的舞台,这个项目coding中肯定还会遇见各种问题的,有问题就在评论区展示出来吧,解决了也可以展示出来,方便后人嘛,哈哈哈哈哈哈

项目源码地址:https://gitee.com/liuyuzhijia/willProject

项目在线体验地址:http://www.lingchang.club/webSocket.jsp

这dome和理论来大部分来源于上面两位大佬,再此对他们表示感谢,我是站在巨人肩膀上的小码农。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值