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

来源:互联网 发布:淘宝上比较好吃的零食 编辑:程序博客网 时间:2024/06/06 06:44

一、前言

      在上一篇博客中,小编简单向大家介绍了一下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的发展,以及数据的传输。