【java】webSocket(二)——实时聊天

一、前言

      在上一篇博客中,小编简单向大家介绍了一下websocket,在这篇博客中小编将通过一个聊天实例来展示一下websocket是如何使用的。

二、资料准备

2.1 环境要求

  • JDK版本在1.7以上

      注:小编刚开始的时候使用的是JDK 1.6 无法运行,原因是websocket是j2ee7规范引入,只要使用支持其标准的服务器就可以运行,所以要在JDK1.7的环境上运行。

2.2 jar包的准备

      我们需要三个jar包:

  • tomcat7-websocket.jar

  • websocket-api.jar

  • gson-2.2.4.jar

      简单介绍:前两个jar包是在tomcat7及以上版本的lib目录下获得的。主要是封装了websocket的API方法类以及实现了其中的方法。gson.jar是一个操作json的jar包。我们用他把字段转换成为json字符串。

这里写图片描述

三、实战操作

      关于实时聊天的需求是这样的,我们有一个登录的页面,输入用户名后,点击登录就可以跳转到聊天窗口。在聊天窗口上就会显示“欢迎XXX来到聊天室~”以及在线的列表中显示在线的人的人名。用户可以发送消息,可以群发,也可以单聊。

3.1 建立web项目

      建立一个名字为chatTest的web项目,把上文提到的jar包导入WEB-INF/lib目录下。

这里写图片描述

3.2 编写启动类

      在src下建立名为com.dmsd.config的包,在此包中建立DemoConfig类,实现ServerApplicationConfig 接口。
      ServerApplicationConfig 是websocket的核心配置类。会在项目启动的时候,自动执行。
实现ServerApplicationConfig后,会有两个方法getAnnotatedEndpointClasses和getEndpointConfigs。

  • getAnnotatedEndpointClasses会扫描src下所有带有@ServerEndPoint注解的类。

  • getEndpointConfigs会获取所有以接口方式配置的websocket类

      DemoConfig :

package com.dmsd.config;

import java.util.Set;

import javax.websocket.Endpoint;
import javax.websocket.server.ServerApplicationConfig;
import javax.websocket.server.ServerEndpointConfig;

public class DemoConfig implements ServerApplicationConfig   {

    public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scan) {
        System.out.println("endPoint扫描到的数量:"+scan.size());
        //返回提供了过滤的作用
        return scan;
    }

    public Set<ServerEndpointConfig> getEndpointConfigs(
            Set<Class<? extends Endpoint>> arg0) {
        return null;
    }
}

3.3 用户登录

      编写用户登录jsp:
      用户登录后,就会提交表单,调用后台的LoginServlet。

<%@ page language="java" import="java.util.*" pageEncoding="GB18030"%>


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>登录</title>

    <script type="text/javascript" src="js/jquery-1.4.4.min.js"></script>
  </head>

  <body>
  <form action="LoginServlet" method="post" name="ff"> 
        name:<input name="username"/><br>
        <input type="submit"/>
  </form>
  </body>
</html>

      LoginServlet :

package com.dmsd.servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class LoginServlet
 */
public class LoginServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public LoginServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        //获取登录提交表单中的用户姓名信息
        String username = request.getParameter("username");
        //把用户姓名存储到session中
        request.getSession().setAttribute("username",username);
        //重定向到chat.jsp
        response.sendRedirect("chat.jsp");
    }

}

3.4 事件操作

      当跳转到chat.jsp页面的时候,会加载其中的js文件,js中会开启一个通信管道。页面加载判断是否已经开启了这个通道,如果没有开启,就开启。当管道开启的时候就会触发onopen事件。触发的方法在ChatSocket类中。

chat.jsp:

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

<title>聊天室</title>
<script type="text/javascript" src="js/jquery-1.4.4.min.js"></script>
<script>
        var ws; //一个ws对象就是一个通信管道!!,只要不关浏览器,不关闭服务器就一直开着
        var target="ws://localhost:8080/chatTest/chatSocket?username=${sessionScope.username}";
        $().ready(function connect() {

                 //页面加载判断是否已经开启了target这个通道,如果没有开启,就开启
                 if ('WebSocket' in window) {
                     ws = new WebSocket(target);
                 } else if ('MozWebSocket' in window) {
                     ws = new MozWebSocket(target);
                 } else {
                     alert('WebSocket is not supported by this browser.');
                     return;
                 } 
                 //接收消息 
                 ws.onmessage = function (event) {
                    eval("var result="+event.data);

                    if(result.alert!=undefined){
                        $("#content").append(result.alert+"<br/>");
                    }

                    if(result.names!=undefined){
                        $("#userList").html("");
                        $(result.names).each(function(){
                            $("#userList").append(this+"<br/>");
                        });
                    }

                    if(result.from!=undefined){
                        $("#content").append(result.from+" "+result.date+
                                " 说:<br/>"+result.sendMsg+"<br/>");
                    }

                 };
             });


        //点击发送消息触发事件
        function send(){
            var msg = $("#msg").val();
            ws.send(msg);
            $("#msg").val("");
        }
    </script>


</head>

<body>
    <h3>欢迎 ${sessionScope.username} 使用本系统!!</h3>

    <div id="content"
        style="
        border: 1px solid black; width: 400px; height: 300px;
        float: left;
    "></div>
    <div id="userList"
        style="
        border: 1px solid black; width: 100px; height: 300px;
        float:left;
    "></div>

    <div style="clear: both;">
        <input id="msg" />
        <button onclick="send();">send</button>
    </div>

</body>
</html>

      在ChatSocket类中,可以把他理解为一个事件操作类,需要添加@ServerEndpoint的注解,这样当系统跑起来的时候,会监控它,来判断是否有推送消息,退出系统,登录系统的操作等等,这样就达到了一个实时的效果。
      在这个类中有以下几种事件:

  • @OnOpen 开启通道的时候触发

  • @OnClose 关闭通道的时候触发

  • @OnMessage 客户端发送数据的时候触发

ChatSocket :

package com.dmsd.socket;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import com.dmsd.vo.Message;
import com.google.gson.Gson;

@ServerEndpoint("/chatSocket")
public class ChatSocket {
    private  static  Set<ChatSocket>  sockets=new HashSet<ChatSocket>();
    private  static  List<String>   nameList=new ArrayList<String>();
    private  Session  session;
    private String username;
    private Gson  gson=new Gson();
    //只要有人连接这个服务,就会打开,执行下面的方法。
    @OnOpen
    public void open(Session session){
        //一个session就代表一个通信会话
        System.out.println("sessionid:"+session.getId()+"通道开启了。。。。");
        //把session添加到容器中
        this.session=session;
        sockets.add(this);

        //getQueryString把url中?后面的所有的串儿都取出来
        String QueryString = session.getQueryString();
        System.out.println(QueryString);
        //获取用户名
        this.username = QueryString.substring(QueryString.indexOf("=")+1);
        nameList.add(username);

        Message message = new Message();
        message.setAlert(username+"进入聊天室!!");
        message.setNames(nameList) ;

        broadcast(sockets, gson.toJson(message) );
    }
    //退出
    @OnClose
    public void close(Session session){
        //1.清理退出的session
        sockets.remove(this);
        //2.清理列表用户名
        nameList.remove(this.username);
        //3.更新消息信息
        Message message=new Message();
        message.setAlert(this.username+"退出聊天室!!");
        message.setNames(nameList);
        //4.广播消息信息
        broadcast(sockets, gson.toJson(message));
    }

    //收
    @OnMessage
    /**
     * 
     * @param session
     * @param msg 从客户端接收的消息
     */
    public void message(Session session,String msg){
        //接收消息

        Message  message=new Message();
        message.setSendMsg(msg);
        message.setFrom(this.username);
        message.setDate(new Date().toString());
        broadcast(sockets, gson.toJson(message));

    }
    /**
     * 广播消息
     * @param ss 用户session
     * @param msg 广播消息
     */
    public void broadcast(Set<ChatSocket>  ss ,String msg ){

        for (Iterator iterator = ss.iterator(); iterator.hasNext();) {
            ChatSocket chatSocket = (ChatSocket) iterator.next();
            try {

                chatSocket.session.getBasicRemote().sendText(msg);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

这里写图片描述

这里写图片描述

四、小结

      通过这次练习,小编把websocket的四个步骤算是搞明白了,知道了具体处理的流程,操作也比较方便了。以后会更好的了解了websocket的发展,以及数据的传输。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你个佬六

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值