springMvc + websocket 实现点对点 聊天通信功能

一,web - demo链接如下(tomcat-websocket):

http://files.cnblogs.com/xiexy/websk.rar

二, springMvc + websocket 实现点对点通信

1,pom.xml 增加spring-websocket.jar

1     <!-- websocket - version须和spring mvc的version保持一致,否则会        
2     出现问题 -->
3     <dependency>
4        <groupId>org.springframework</groupId>
5        <artifactId>spring-websocket</artifactId>
6        <version>${spring.version}</version>
7     </dependency>

2,登陆  - login.jsp

<%@ 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 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>socket - login</title>
</head>
<body>
<center>
    <form action="websocket/login.do" method="post">
        <table>
            <tr>
                <td>username:</td><td><input type="text" id="username" name="username"/></td>
            </tr>
            <tr>
                <td colspan="2"> <input type="submit" value="登录"/></td>
            </tr>
        </table>
    </form>
</center>
</body>
</html>
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.socket.TextMessage;

import com.aisino.core.user.entity.User;

@RequestMapping("websocket")
@Controller
public class UserController {

    @Autowired
    private MsgScoketHandle msgScoketHandle;

    @RequestMapping("login")
    public String login(String username, HttpServletRequest request){
        User user = new User();
        user.setReal_name(username);
        request.getSession().setAttribute("user",user);
        request.getSession().setAttribute("username", username);
        return "soket/soket";
    }
    
    

    @ResponseBody
    @RequestMapping("sendMsg")
    public String sendMag(String content,String toUserName){
        User user = new User();
        user.setReal_name(toUserName);
        TextMessage textMessage = new TextMessage(content);
        msgScoketHandle.sendMessageToUser(user,textMessage);
        return "200";
    }
}

3,点对点通信  socket - chat.jsp

<%@ 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 Transitional//EN">
<html>
<head>

<base href="<%=basePath%>">
<title>socket - chat</title>
<script type="text/javascript" src="plug-in/jquery/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="views/soket/sockjs.min.js"></script>
</head>
 
<body>
    当前登录用户:${username}<br>
    
    <input type="text" id="text">
    <button id="btn1" value="发送给后台">发送给后台</button>
    <button id="btn2" value="发送给其他用户">发送给其他用户</button>
    <div id="msg"></div>
</body>

<script type="text/javascript">
$(document).ready(function() {
    var ws;
    if ('WebSocket' in window) {
        ws = new WebSocket("ws://"+window.location.host+"/robot/webSocketServer");
    } else if ('MozWebSocket' in window) {
        ws = new MozWebSocket("ws://"+window.location.host+"/robot/webSocketServer");
    } else {
        //如果是低版本的浏览器,则用SockJS这个对象,对应了后台“sockjs/webSocketServer”这个注册器,
        //它就是用来兼容低版本浏览器的
        ws = new SockJS("http://"+window.location.host+"/robot/sockjs/webSocketServer");
    }
    ws.onopen = function (evnt) {
    };
    //接收到消息
    ws.onmessage = function (evnt) {
        alert(evnt.data);
        $("#msg").html(evnt.data);
    };
    ws.onerror = function (evnt) {
        console.log(evnt)
    };
    ws.onclose = function (evnt) {
    }

    $("#btn1").click(function () {
        ws.send($("#text").val());
    });
    $("#btn2").bind("click",function () {
        var url = "${pageContext.request.contextPath}/websocket/sendMsg";
        var content =  $("#text").val();
        var toUserName = "laoliu";//与老刘通信
        $.ajax({
            data: "content=" + content + "&toUserName=" + toUserName,
            type: "get",
            dataType: 'text',
            async: false,
            contentType: "application/x-www-form-urlencoded;charset=UTF-8",
            encoding: "UTF-8",
            url: url,
            success: function (data) {
                alert(data.toString());
            },
            error: function (msg) {
                alert(msg);
            },

        });

    })
});
</script>
</html>
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

@Configuration
@EnableWebMvc
@EnableWebSocket
public class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer{

    private static final Logger logger = LoggerFactory.getLogger(WebSocketConfig.class);
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        System.out.println("==========================注册socket");
        //注册websocket server实现类,"/webSocketServer"访问websocket的地址
        registry.addHandler(msgSocketHandle(),
                "/webSocketServer").
                addInterceptors(new WebSocketHandshakeInterceptor());
        //使用socketjs的注册方法
        registry.addHandler(msgSocketHandle(),
                "/sockjs/webSocketServer").
                addInterceptors(new WebSocketHandshakeInterceptor())
                .withSockJS();
    }

     /**
     *
     * @return 消息发送的Bean
     */
    @Bean(name = "msgSocketHandle")
    public WebSocketHandler msgSocketHandle(){
        return new MsgScoketHandle();
    }
}
import java.util.Map;

import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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 com.aisino.core.user.entity.User;

public class WebSocketHandshakeInterceptor implements HandshakeInterceptor {
   private static final Logger logger = LoggerFactory.getLogger(WebSocketHandshakeInterceptor.class);

    /**
     * 握手前
     * @param request
     * @param response
     * @param webSocketHandler
     * @param attributes
     * @return
     * @throws Exception
     */
    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler webSocketHandler, Map<String, Object> attributes) throws Exception {
        logger.info("握手操作");
        if (request instanceof ServletServerHttpRequest){
           ServletServerHttpRequest servletServerHttpRequest = (ServletServerHttpRequest) request;
           HttpSession session = servletServerHttpRequest.getServletRequest().getSession(false);
           if(session != null){
                //从session中获取当前用户
               User user = (User) session.getAttribute("user");
               attributes.put("user",user);
           }
       }

        return true;
    }

    /**
     * 握手后
     * @param serverHttpRequest
     * @param serverHttpResponse
     * @param webSocketHandler
     * @param e
     */
    @Override
    public void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Exception e) {

    }
}
import java.io.IOException;
import java.util.ArrayList;

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 com.aisino.core.user.entity.User;
import com.google.common.collect.Lists;

@Component
public class MsgScoketHandle implements WebSocketHandler {

    /**已经连接的用户*/
    private static final ArrayList<WebSocketSession> users;

    static {
        //保存当前连接用户
        users = Lists.newArrayList();
    }

    /**
     * 建立链接
     * @param webSocketSession
     * @throws Exception
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession webSocketSession) throws Exception {
        //将用户信息添加到list中
        users.add(webSocketSession);
        System.out.println("=====================建立连接成功==========================");
        User user  = (User) webSocketSession.getAttributes().get("user");
        if(user != null){
            System.out.println("当前连接用户======"+user.getReal_name());
        }
        System.out.println("webSocket连接数量====="+users.size());
    }

    /**
     * 接收消息
     * @param webSocketSession
     * @param webSocketMessage
     * @throws Exception
     */
    @Override
    public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> webSocketMessage) throws Exception {
        User user = (User) webSocketSession.getAttributes().get("user");
        System.out.println("收到用户:"+user.getReal_name()+"的消息");
        System.out.println(webSocketMessage.getPayload().toString());
        System.out.println("===========================================");

    }

    /**
     * 异常处理
     * @param webSocketSession
     * @param throwable
     * @throws Exception
     */
    @Override
    public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable){
        if (webSocketSession.isOpen()){
            //关闭session
            try {
                webSocketSession.close();
            } catch (IOException e) {
            }
        }
        //移除用户
        users.remove(webSocketSession);
    }

    /**
     * 断开链接
     * @param webSocketSession
     * @param closeStatus
     * @throws Exception
     */
    @Override
    public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception {
        users.remove(webSocketSession);
        User user = (User) webSocketSession.getAttributes().get("user");
        System.out.println(user.getReal_name()+"断开连接");
    }

    @Override
    public boolean supportsPartialMessages() {
        return false;
    }

    /**
     * 发送消息给指定的用户
     * @param user
     * @param messageInfo
     */
    public void sendMessageToUser(User user, TextMessage messageInfo){
        for (WebSocketSession session : users) {
            User sessionUser = (User) session.getAttributes().get("user");
            //根据用户名去判断用户接收消息的用户
            if(user.getReal_name().equals(sessionUser.getReal_name())){
                try {
                    if (session.isOpen()){
                        session.sendMessage(messageInfo);
                        System.out.println("发送消息给:"+user.getReal_name()+"内容:"+messageInfo);
                    }
                    break;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

4,注意点,使用Tomcat8以上,tomcat7会报错(貌似与tomat-websocket 冲突)

 demo地址:https://files.cnblogs.com/files/xiexy/springMvc-websocket.zip

原文地址:https://www.cnblogs.com/xiexy/p/4070562.html