Spring-WebScoket

来源:互联网 发布:中国房地产未来知乎 编辑:程序博客网 时间:2024/04/27 22:04

1.Pom.xml

    <dependencies>        <dependency>            <groupId>com.fasterxml.jackson.core</groupId>            <artifactId>jackson-annotations</artifactId>            <version>2.3.0</version>        </dependency>        <dependency>            <groupId>com.fasterxml.jackson.core</groupId>            <artifactId>jackson-core</artifactId>            <version>2.3.1</version>        </dependency>        <dependency>            <groupId>com.fasterxml.jackson.core</groupId>            <artifactId>jackson-databind</artifactId>            <version>2.3.3</version>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-messaging</artifactId>            <version>4.0.5.RELEASE</version>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-websocket</artifactId>            <version>4.0.5.RELEASE</version>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-webmvc</artifactId>            <version>4.0.5.RELEASE</version>        </dependency>        <dependency>            <groupId>com.google.code.gson</groupId>            <artifactId>gson</artifactId>            <version>2.3.1</version>        </dependency>        <dependency>            <groupId>javax.servlet</groupId>            <artifactId>javax.servlet-api</artifactId>            <version>3.1.0</version>            <scope>provided</scope>        </dependency>        <dependency>            <groupId>junit</groupId>            <artifactId>junit</artifactId>            <version>3.8.1</version>            <scope>test</scope>        </dependency>    </dependencies>

2.客户端的连接

<%@ 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 + "/";%>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>

3.编码实现

1.WebScoket配置处理器

import javax.annotation.Resource;import org.springframework.stereotype.Component;import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;import org.springframework.web.socket.config.annotation.EnableWebSocket;import org.springframework.web.socket.config.annotation.WebSocketConfigurer;import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;/** * WebScoket配置处理器 * @author Goofy * @Date 2015年6月11日 下午1:15:09 */@Component@EnableWebSocketpublic 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();    }}

2.Socket建立连接(握手)和断开

import java.util.Map;import javax.servlet.http.HttpSession;import org.springframework.http.server.ServerHttpRequest;import org.springframework.http.server.ServerHttpResponse;import org.springframework.http.server.ServletServerHttpRequest;import org.springframework.web.socket.WebSocketHandler;import org.springframework.web.socket.server.HandshakeInterceptor;import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;/** * Socket建立连接(握手)和断开 *  * @author Goofy * @Date 2015年6月11日 下午2:23:09 */public class HandShake extends HttpSessionHandshakeInterceptor {    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) {//instanceof通过返回一个布尔值来指出,这个对象是否是这个特定类或者是它的子类的一个实例            ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;            HttpSession session = servletRequest.getServletRequest().getSession(false);//如果当前session没有就返回null            // 标记用户            Long uid = (Long) session.getAttribute("uid");//登陆用户ID            if(uid!=null){                attributes.put("uid", uid);            }else{                System.out.println("beforeHandshake运行结束  false");                return false;            }        }        return true;    }    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {        super.afterHandshake(request, response, wsHandler, exception);      }}

3.Socket处理器

package org.xdemo.example.websocket.websocket;import java.io.IOException;import java.text.SimpleDateFormat;import java.util.Date;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.Map.Entry;import org.springframework.stereotype.Component;import org.springframework.web.socket.CloseStatus;import org.springframework.web.socket.TextMessage;import org.springframework.web.socket.WebSocketHandler;import org.springframework.web.socket.WebSocketMessage;import org.springframework.web.socket.WebSocketSession;import org.xdemo.example.websocket.entity.Message;import com.google.gson.Gson;import com.google.gson.GsonBuilder;/** * Socket处理器 *  * @author Goofy * @Date 2015年6月11日 下午1:19:50 */@Componentpublic 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);//当前登陆用户与登陆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);        }    }}

PS:使用的是Tomcat8.5

https://github.com/Amant-huangqi/spring-websocket