WebSocket学习笔记

H5的新规范,强调实时性,websocket传输的都是字符串。传统中的web请求-响应模式中实时传输的实现,comet可以一定程度上模拟双向通信,但是效率较低,并且需要服务器较好的支持,还有flash中的socket和xmlsocket可以真正的实现双向通信,通过flex ajax bridge,可以在js中使用这两个功能。而H5定义的websocket协议是将代替上面两个技术,它是建立在http协议的基础之上,可以更好的节省服务器资源和带宽并且达到实时通信,JavaEE7也实现了该协议。主要实现的是4个操作,在B-S的架构下面,客户端可以进行取放、服务器拿取的操作以及客户端进行拿取,服务器进行取放。
说明】这里的利用Tomcat自带的一个Demo,自己实现。这里新建WEB项目的时候直接引入Tomcat的目录即可,不再需要其他的jar包,这里我们用到的是两个jar,一个是tomcat7-websocket.jar和websocket-api.jar,前者实现了后者的接口。

DEMO 1

(Eclipse–>WebSocketTest)
首先是一个配置类:

package com.hhu.config;

import java.util.Set;

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

//这里实现的是ServerApplicationConfig,有两个方法,一种是注解启动,一种接口启动
//这是一个启动类
public class DemoConfig implements ServerApplicationConfig {

    //注解方式 启动,这里它是自动执行的,自动扫描带有@ServerEndPoint(即终端)注解的类来自动注册
    //这里我们通常都是用注解的方式来完成
    @Override
    public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scan) {
        System.out.println("config.........." + scan.size());

        //返回scan,如果返回,服务器不会帮助注册任何Socket,提供了一定的过滤作用
        return scan;
    }

    //接口方式 启动,由于使用了注解的方式,那这个接口的方式我们不予关注
    @Override
    public Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> arg0) {
        // TODO Auto-generated method stub
        return null;
    }

}

然后写Socket,这里包含了服务端对客户端所有的响应

package com.hhu.socket;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

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

/**
 * 就是Socket
 * @author Weiguo Liu
 *
 */
@ServerEndpoint("/echo")
public class EchoSocket {

    //用来查看单例还是多例的
    public EchoSocket() {
        System.out.println("EchoSocket.EchoSocket()");
    }

    /*这个注解表示只要有人链接这个Socket,这个方法就会执行
    *带进来一个Session,一个管道(会话)代表一次Session
    */
    @OnOpen
    public void open(Session session) {
        //一个Session代表一个通信会话(不同的客户端链接他们的建立的session的id不一样)
        System.out.println("已进入open方法,session的id:" + session.getId());
    }

    /*
     * 浏览器关闭的时候,自动调用@OnClose的方法,表示session会话结束
     */
    @OnClose
    public void close(Session session){
        System.out.println("当前session关闭:session.id" + session.getId());
    }

    /*
     * 服务端接受客户端发送的信息之后所要执行的方法
     */
    @OnMessage
    public void message(Session session,String msg) throws IOException {
        System.out.println("客户端说" + msg);

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
        Date date = new Date();
        String now = sdf.format(date);
        //这里服务端也可以给客户端发送消息,当然如果是其他类别的消息需要用不同的sendxxx()方法
        session.getBasicRemote().sendText(now + ":我是服务器,我已经接受你的消息,客户端说“" + msg + "”");
    }
}

前端的页面也很简单:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
<body>
<h2>Hello World!</h2>

<input id="msg"/>

<button onclick="subOpen()">链接</button>
<button onclick="subSend()">发送</button>

<div id="servermsg"></div>


<script type="text/javascript">
    var ws; //一个ws对象就是一个通信管道
    //target表示的是请求地址,你要链接谁
    var target = "ws://localhost:8080/WebSocketTest/echo";


    function subOpen(){
        if('WebSocket'in window) {
            ws = new WebSocket(target);
        } else if('MozWebSocket'in window) {
            ws = new MozWebSocket(target);
        } else {
            alert("当前浏览器不支持WebSocket!");
            return;
        }

        //客户端从服务端接收信息也是基于事件的,异步,所以在open的时候就要注册一个message
        ws.onmessage = function(MsgEvent) {//这里返回的是一个事件对象!!
            console.info(MsgEvent.data);//真实的服务端发送的消息在事件对象的data变量中
            //往div中注入内容用document.getElementById("divid").innerHTML
            //追加内容的时候就用+=,不追加就直接用=就好
            document.getElementById("servermsg").innerHTML += MsgEvent.data;
        }
    }

    //发送消息
    function subSend() {
        //获取输入框的内容
        var msg = document.getElementById("msg").value;
        //发送消息(客户端给服务端发送消息)
        ws.send(msg);
        //清空输入框中的内容
        document.getElementById("msg").value = "";
    }


</script>
</body>
</html>

Demo2:聊天室–群聊+私聊

(Eclipse–>WebChat)
第二个Demo是实现了一个聊天室的常规功能:群聊和私聊,其实就是服务端向客户端发送消息所选择的Session不同而已其他的还是一样的。

还是一样,配置不能少:

package com.hhu.config;

import java.util.Set;

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

//这里实现的是ServerApplicationConfig,有两个方法,一种是注解启动,一种接口启动
//这是一个启动类
public class DemoConfig implements ServerApplicationConfig {

    //注解方式 启动,这里它是自动执行的,自动扫描带有@ServerEndPoint(即终端)注解的类来自动注册
    //这里我们通常都是用注解的方式来完成,有几个类(加了注解的)scan的size()就是多少
    @Override
    public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scan) {
        System.out.println("config.........." + scan.size());

        //返回scan,如果返回,服务器不会帮助注册任何Socket,提供了一定的过滤作用
        return scan;
    }

    //接口方式 启动,由于使用了注解的方式,那这个接口的方式我们不予关注
    @Override
    public Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> arg0) {
        // TODO Auto-generated method stub
        return null;
    }

}

然后是webSocket

package com.hhu.socket;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

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

import com.google.gson.Gson;
import com.hhu.util.ContentVo;
import com.hhu.util.Message;

/**
 * 建立聊天室的webSocket程序
 * @author Weiguo Liu
 *
 */

//标记前台请求的地址
@ServerEndpoint("/chatSocket")
public class ChatSocket {

    private String username;
    //这里声明为static类型的变量是为了将sessions整个变量变为公共的变量才能共同使用
    private static List<Session> sessions = new ArrayList<Session>();

    private static List<String> names = new ArrayList<String>();

    private static Map<String,Session> map = new HashMap<String,Session>();

    //在聊天室链接后(即成功创建聊天室的Socket)所要干的事儿
    @OnOpen
    public void open(Session session) {

        //这里的session和Servlet中的session不是同一个session,
        //要获取用户的名字,就要先从Servlet中获取,然后再在请求的时候将参数传过来即可
        //getQueryString()可以将问号后面全部拿出来,在SpringMVC中又是不一样的
        String user = session.getQueryString();

        //将username=xx中的xx取出来
        username = user.split("=")[1];


        //将当前的session放到List中
        this.sessions.add(session);

        //将用户添加进List
        this.names.add(username);

        this.map.put(this.username, session);

        Message msg = new Message();
        msg.setWelcom("欢迎" + this.username + "进入聊天室!");
        msg.setUsernames(names);

        //进行广播,将这条消息广播到每一个session中
        broadcast(this.sessions, msg.toJson());
    }




    //进行广播,将消息发送给每个session中,需要遍历每一个session
    public void broadcast(List<Session> ss,String msg) {
        Iterator<Session> iterator=ss.iterator();
        while(iterator.hasNext()){
            //获取每个通信通道
            Session session = (Session)iterator.next();
            try {
                //向每个用户广播一条消息
                session.getBasicRemote().sendText(msg);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    } 

    //session关闭时候的触发的方法
    @OnClose
    public void close(Session session) {
        //在浏览器关闭时需要,将该session从List中移除,否则再进行广播的时候,该还会遍历这
        //个已经移除的session,将会报错
        this.sessions.remove(session);
        this.names.remove(this.username);

        Message message = new Message();
        message.setWelcom(this.username + "已退出聊天室!");
        message.setUsernames(this.names);

        broadcast(this.sessions, message.toJson());
    }

    private static Gson gson = new Gson();

    //接受到来自客户端发送的消息
    @OnMessage
    public void message(Session session, String json) {

        //将json字符串转成ContentVo对象
        ContentVo vo = gson.fromJson(json, ContentVo.class);

        if(vo.getType()==1) {//广播
            Message message = new Message();
            message.setContent(this.username,vo.getMsg());
            //这里不再是广播,而是选择性进行发送
            broadcast(sessions, message.toJson());
        } else {//单聊
            String to = vo.getTo();
            Session to_session = this.map.get(to);

            Message message = new Message();
            message.setContent(this.username, "<font color=red>私聊:</font>"+vo.getMsg());

            try {
                //发送消息
                to_session.getBasicRemote().sendText(message.toJson());
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }


    }

}

登录跳转的Servlet:

package com.hhu.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 {
        //从提交的表单中获取“username”的值
        String username = request.getParameter("username");
        System.out.println("进入Servelet");
        //将这个名字放到session中
        request.getSession().setAttribute("username", username);

        System.out.println("表单提交成功username=" + username);
        //跳转到另一页面 
        response.sendRedirect("chart.jsp");
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

两个用于发送消息的工具类

package com.hhu.util;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import com.google.gson.Gson;

/**
 * 消息包装类
 * @author Weiguo Liu
 *
 */
public class Message {
    private String welcom;

    private List<String> usernames;

    private String content;

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public void setContent(String name,String msg) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
        this.content = sdf.format(new Date()) + "<br/>" + name + ":" + msg + "<br/>";
    }

    public String getWelcom() {
        return welcom;
    }

    public void setWelcom(String welcom) {
        this.welcom = welcom;
    }

    public List<String> getUsernames() {
        return usernames;
    }

    public void setUsernames(List<String> usernames) {
        this.usernames = usernames;
    }

    public Message() {
        super();
    }

    private static Gson gson = new Gson();

    public String toJson() {
        return gson.toJson(this);
    }

    @Override
    public String toString() {
        return "Message [welcom=" + welcom + ", usernames=" + usernames + "]";
    }

}
package com.hhu.util;

public class ContentVo {

    private String to;
    private String msg;
    private Integer type;

    public String getTo() {
        return to;
    }

    public void setTo(String to) {
        this.to = to;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Integer getType() {
        return type;
    }

    public void setType(Integer type) {
        this.type = type;
    }

}

最后是登录界面只是简单的进行模拟,这里仅给出聊天室的界面

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page isELIgnored="false"%>
<!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>
<script type="text/javascript" src="${pageContext.request.contextPath }/resources/jquery-3.2.1.min.js"></script>
<script type="text/javascript">
    //var username = "${sessionScope.username}";
    /*当然也可以用上面的写法,这里需要注意的是一定要加引号,通过el表达式获取的是
    *一个变量,只有加了引号才是字符串
    */
    var username = '${username}';
    //进入页面就直接打开socket通道
    var ws;
    var target = "ws://localhost:8080/WebChat/chatSocket?username="+username;
    window.onload = function() { 

        //判定浏览器是否支持websocket协议
        if('WebSocket' in window) {
            ws = new WebSocket(target);
        } else if('MoWebSocket' in window) {
            ws = new MozWebSocket(target);
        } else {
            alert("当前浏览器不支持WebSocket");
            return;
        }


        //接受来自服务器的消息,返回一个事件对象,具体的返回内容在data属性中
        ws.onmessage = function(event) {
            //由于传过来的变成了json内容的字符串,所以这里所处理,eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码
            eval("var msg=" + event.data + ";");

            if(undefined!=msg.welcom){
                //在div中追加消息
                $("#content").append(msg.welcom+"</br>");
            }

            if(undefined!=msg.usernames){
                //刷新的时候清空用户列表,否则刷新会造成用户的重复添加
                $("#userList").html("");
                //这是遍历的用户列表
                $(msg.usernames).each(function(){
                    $("#userList").append("<input type=checkbox value='" + this +"'/>" + this + "</br>");
                });
            }

            //接受到服务端的消息后
            if(undefined!=content) {
                //在聊天追加用户发送的内容
                $("#content").append(msg.content);
            }


        }

    }

    //向后发送消息
    function subSend() {
        //获取输入框中的值,这里的获取和清空都是jquery中的写法
        var val = $("#msg").val();
        console.info("msg===" + val);

        //清空输入框中的值
        $("#msg").val("");

        //获取复选框选中了几个,这里注意有的时候写成size(),有时写成length,根据jquery的版本不同做适当调整
        console.info($('#userList :checked').length);


        var obj = null;

        if($('#userList :checked').length==0) {
            obj = {
                msg:val,
                type:1//1表示广播 2表示单聊
            }
        } else {

            //获取发送对象,即复选框中的选中值
            var to = $('#userList :checked').val();
            //获取复选框中的选中值
            console.info(to);

            obj = {
                to:to,
                msg:val,
                type:2//1表示广播 2表示单聊
            }
        }

        var str = JSON.stringify(obj);//将obj转换成JSON字符串
        ws.send(str);
        $("#msg").val("");
    }

</script>
</head>
<body>
    <!--聊天的主体窗口  -->
    <div id="container" style="border: 1px solid black;width: 400px;height: 400px;float: left;">
        <div id="content" style="height: 350px;">

        </div>
        <div style="border-top: 1px solid black;width: 400px;height: 55px;">
            <input id="msg" style="border: 1px solid white;width: 348px;height:55px;"/>
            <button onclick="subSend()">发送</button>
        </div>
    </div>

    <!-- 聊天用户列表 -->
    <div id="userList" style="border: 1px solid black;width: 100px;height: 390px;float: left;">

    </div>

</body>
</html>

最后再来一个在线聊天的加强版来说明SpringMVC中websocket的使用,这个案例很管用!!!

(Eclipse–>SpringWebSocket)
websocket的配置文件

/**
 * WebScoket配置处理器
 */
@Component
@EnableWebSocket
public class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {

    @Resource
    MyWebSocketHandler handler;

    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(handler, "/ws").addInterceptors(new HandShake());

        registry.addHandler(handler, "/ws/sockjs").addInterceptors(new HandShake()).withSockJS();
    }

}

HandShake处理类

/**
 * 每次建立连接都会进行握手
 * @author Weiguo Liu
 *
 */
public class HandShake implements HandshakeInterceptor {

    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
        System.out.println("Websocket:用户[ID:" + ((ServletServerHttpRequest) request).getServletRequest().getSession(false).getAttribute("uid") + "]已经建立连接");
        if (request instanceof ServletServerHttpRequest) {
            ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
            HttpSession session = servletRequest.getServletRequest().getSession(false);
            // 标记用户
            Long uid = (Long) session.getAttribute("uid");
            if(uid!=null){
                attributes.put("uid", uid);
            }else{
                return false;
            }
        }
        return true;
    }

    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
    }

}

拦截器

@Component
public class MyWebSocketHandler implements WebSocketHandler {

    public static final Map<Long, WebSocketSession> userSocketSessionMap;

    static {
        userSocketSessionMap = new HashMap<Long, WebSocketSession>();
    }

    /**
     * 建立连接后
     */
    public void afterConnectionEstablished(WebSocketSession session)
            throws Exception {
        Long uid = (Long) session.getAttributes().get("uid");
        if (userSocketSessionMap.get(uid) == null) {
            userSocketSessionMap.put(uid, session);
        }
    }

    /**
     * 消息处理,在客户端通过Websocket API发送的消息会经过这里,然后进行相应的处理
     */
    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
            if(message.getPayloadLength()==0)return;
            Message msg=new Gson().fromJson(message.getPayload().toString(),Message.class);
            msg.setDate(new Date());
            sendMessageToUser(msg.getTo(), new TextMessage(new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create().toJson(msg)));
    }

    /**
     * 消息传输错误处理
     */
    public void handleTransportError(WebSocketSession session,
            Throwable exception) throws Exception {
        if (session.isOpen()) {
            session.close();
        }
        Iterator<Entry<Long, WebSocketSession>> it = userSocketSessionMap
                .entrySet().iterator();
        // 移除Socket会话
        while (it.hasNext()) {
            Entry<Long, WebSocketSession> entry = it.next();
            if (entry.getValue().getId().equals(session.getId())) {
                userSocketSessionMap.remove(entry.getKey());
                System.out.println("Socket会话已经移除:用户ID" + entry.getKey());
                break;
            }
        }
    }

    /**
     * 关闭连接后
     */
    public void afterConnectionClosed(WebSocketSession session,
            CloseStatus closeStatus) throws Exception {
        System.out.println("Websocket:" + session.getId() + "已经关闭");
        Iterator<Entry<Long, WebSocketSession>> it = userSocketSessionMap
                .entrySet().iterator();
        // 移除Socket会话
        while (it.hasNext()) {
            Entry<Long, WebSocketSession> entry = it.next();
            if (entry.getValue().getId().equals(session.getId())) {
                userSocketSessionMap.remove(entry.getKey());
                System.out.println("Socket会话已经移除:用户ID" + entry.getKey());
                break;
            }
        }
    }

    public boolean supportsPartialMessages() {
        return false;
    }

    /**
     * 给所有在线用户发送消息
     * 
     * @param message
     * @throws IOException
     */
    public void broadcast(final TextMessage message) throws IOException {
        Iterator<Entry<Long, WebSocketSession>> it = userSocketSessionMap
                .entrySet().iterator();

        // 多线程群发
        while (it.hasNext()) {

            final Entry<Long, WebSocketSession> entry = it.next();

            if (entry.getValue().isOpen()) {
                // entry.getValue().sendMessage(message);
                new Thread(new Runnable() {

                    public void run() {
                        try {
                            if (entry.getValue().isOpen()) {
                                entry.getValue().sendMessage(message);
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }

                }).start();
            }

        }
    }

    /**
     * 给某个用户发送消息
     * 
     * @param userName
     * @param message
     * @throws IOException
     */
    public void sendMessageToUser(Long uid, TextMessage message)
            throws IOException {
        WebSocketSession session = userSocketSessionMap.get(uid);
        if (session != null && session.isOpen()) {
            session.sendMessage(message);
        }
    }

}

Spring中的配置:

    <mvc:annotation-driven />

    <mvc:resources location="/resources/" mapping="/resources/**" />

    <context:component-scan base-package="com.hhu" />

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/" />
        <property name="suffix" value=".jsp" />
        <property name="order" value="1" />
    </bean>

web.xml中常规配置即可,记得加上Spring的DispatcherServlet

前端界面

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
    String path = request.getContextPath();
    String basePath = request.getServerName() + ":"
            + request.getServerPort() + path + "/";
    String basePath2 = request.getScheme() + "://"
            + request.getServerName() + ":" + request.getServerPort()
            + path + "/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
<script type="text/javascript" src="<%=basePath2%>resources/jquery.js"></script>
<style>
textarea {
    height: 300px;
    width: 100%;
    resize: none;
    outline: none;
}

input[type=button] {
    float: right;
    margin: 5px;
    width: 50px;
    height: 35px;
    border: none;
    color: white;
    font-weight: bold;
    outline: none;
}

.clear {
    background: red;
}

.send {
    background: green;
}

.clear:active {
    background: yellow;
}

.send:active {
    background: yellow;
}

.msg {
    width: 100%;
    height: 25px;
    outline: none;
}

#content {
    border: 1px solid gray;
    width: 100%;
    height: 400px;
    overflow-y: scroll;
}

.from {
    background-color: green;
    width: 80%;
    border-radius: 10px;
    height: 30px;
    line-height: 30px;
    margin: 5px;
    float: left;
    color: white;
    padding: 5px;
    font-size: 22px;
}

.to {
    background-color: gray;
    width: 80%;
    border-radius: 10px;
    height: 30px;
    line-height: 30px;
    margin: 5px;
    float: right;
    color: white;
    padding: 5px;
    font-size: 22px;
}

.name {
    color: gray;
    font-size: 12px;
}

.tmsg_text {
    color: white;
    background-color: rgb(47, 47, 47);
    font-size: 18px;
    border-radius: 5px;
    padding: 2px;
}

.fmsg_text {
    color: white;
    background-color: rgb(66, 138, 140);
    font-size: 18px;
    border-radius: 5px;
    padding: 2px;
}

.sfmsg_text {
    color: white;
    background-color: rgb(148, 16, 16);
    font-size: 18px;
    border-radius: 5px;
    padding: 2px;
}

.tmsg {
    clear: both;
    float: right;
    width: 80%;
    text-align: right;
}

.fmsg {
    clear: both;
    float: left;
    width: 80%;
}
</style>
<script>
        var path = '<%=basePath%>';
        var uid=${uid eq null?-1:uid};
        if(uid==-1){
            location.href="<%=basePath2%>";
        }
        var from=uid;
        var fromName='${name}';
        var to=uid==1?2:1;

        var websocket;
        if ('WebSocket' in window) {
            websocket = new WebSocket("ws://" + path + "/ws?uid="+uid);
        } else if ('MozWebSocket' in window) {
            websocket = new MozWebSocket("ws://" + path + "/ws"+uid);
        } else {
            websocket = new SockJS("http://" + path + "/ws/sockjs"+uid);
        }
        websocket.onopen = function(event) {
            console.log("WebSocket:已连接");
            console.log(event);
        };
        websocket.onmessage = function(event) {
            var data=JSON.parse(event.data);
            console.log("WebSocket:收到一条消息",data);
            var textCss=data.from==-1?"sfmsg_text":"fmsg_text";
            $("#content").append("<div class='fmsg'><label class='name'>"+data.fromName+"&nbsp;"+data.date+"</label><div class='"+textCss+"'>"+data.text+"</div></div>");
            scrollToBottom();
        };
        websocket.onerror = function(event) {
            console.log("WebSocket:发生错误 ");
            console.log(event);
        };
        websocket.onclose = function(event) {
            console.log("WebSocket:已关闭");
            console.log(event);
        }
            function sendMsg(){
                var v=$("#msg").val();
                if(v==""){
                    return;
                }else{
                    var data={};
                    data["from"]=from;
                    data["fromName"]=fromName;
                    data["to"]=to;
                    data["text"]=v;
                    websocket.send(JSON.stringify(data));
                    $("#content").append("<div class='tmsg'><label class='name'>我&nbsp;"+new Date().Format("yyyy-MM-dd hh:mm:ss")+"</label><div class='tmsg_text'>"+data.text+"</div></div>");
                    scrollToBottom();
                    $("#msg").val("");
                }
            }

            function scrollToBottom(){
                var div = document.getElementById('content');
                div.scrollTop = div.scrollHeight;
            }

            Date.prototype.Format = function (fmt) { //author: meizz 
                var o = {
                    "M+": this.getMonth() + 1, //月份 
                    "d+": this.getDate(), //日 
                    "h+": this.getHours(), //小时 
                    "m+": this.getMinutes(), //分 
                    "s+": this.getSeconds(), //秒 
                    "q+": Math.floor((this.getMonth() + 3) / 3), //季度 
                    "S": this.getMilliseconds() //毫秒 
                };
                if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
                for (var k in o)
                if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
                return fmt;
            }

            function send(event){
                var code;
                 if(window.event){
                     code = window.event.keyCode; // IE
                 }else{
                     code = e.which; // Firefox
                 }
                if(code==13){ 
                    sendMsg();            
                }
            }

            function clearAll(){
                $("#content").empty();
            }
        </script>
</head>
<body>
    欢迎:${sessionScope.name }
    <div id="content"></div>
    <input type="text" placeholder="请输入要发送的信息" id="msg" class="msg" onkeydown="send(event)">
    <input type="button" value="发送" class="send" onclick="sendMsg()" >
    <input type="button" value="清空" class="clear" onclick="clearAll()">
</body>
</html>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
    String path = request.getContextPath();
    String basePath= request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
<script type="text/javascript" src="<%=basePath%>resources/jquery.js"></script>
<script type="text/javascript">
    var path='<%=basePath%>';
    function broadcast(){
        $.ajax({
            url:path+'msg/broadcast',
            type:"post",
            data:{text:$("#msg").val()},
            dataType:"json",
            success:function(data){
                alert("发送成功");
            }
        });
    }
</script>
</head>
<body>
    发送广播
    <textarea style="width:100%;height:300px;" id="msg" ></textarea>
    <input type="button" value="发送" onclick="broadcast()">
</body>
</html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值