Spring-WebSocket实现

之前刚写了java 本身的websocket,再使用spring中的websocket,理解起来就比较容易了;
spring 中多出了 WebSocket握手请求的拦截器, 继承 Interface HandshakeInterceptor;
具体的过程跟 java 没什么区别;
按照执行顺序贴出代码:
index.jsp:

<body>
<form action="msg/login" method="post">
    用户名:
    <select name="id">
        <option value="1">张三</option>
        <option value="2">李四</option>
        <option value="3">王五</option>
    </select><br>
    密码:
    <input name="password" type="text" value="123456">
    <input type="submit" value="登录">
</form>
</body>

ChatController:

package com.controller;


import com.entity.User;
import com.handler.MyWebSocketHandler;
import com.sun.org.glassfish.gmbal.ParameterNames;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import javax.jws.WebParam;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

@Controller
@RequestMapping(value =  "/msg" )

public class ChatController {

    @Autowired
    private MyWebSocketHandler handler;
    Map<Long, User> users = new HashMap<Long, User>();
    // 模拟一些数据
    @ModelAttribute
    public void setReqAndRes() {
        User u1 = new User();
        u1.setId(1l);
        u1.setName("张三");
        users.put(u1.getId(), u1);

        User u2 = new User();
        u2.setId(2L);
        u2.setName("李四");
        users.put(u2.getId(), u2);

        User u3 = new User();
        u3.setId(3L);
        u3.setName("王五");
        users.put(u3.getId(), u3);
    }


    @RequestMapping(value = "/login",method = RequestMethod.POST)
    public ModelAndView login(User user, HttpServletRequest request){
        request.getSession().setAttribute("uid",user.getId());
        request.getSession().setAttribute("name",users.get(user.getId()).getName());
        return new ModelAndView("redirect:talk");
    }
    @RequestMapping(value = "/talk",method = RequestMethod.GET)
    public ModelAndView talk(){
        return new ModelAndView("talk");
    }


}

talk.jsp:

<%@ 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};--%>
        var uid = ${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>
    欢迎:${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>

WebSocketConfig :

package com.config;


import com.handler.MyWebSocketHandler;
import com.interceptor.HandShake;
import org.springframework.beans.factory.annotation.Autowired;
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;

import javax.annotation.Resource;

@Component
@EnableWebSocket
public class WebSocketConfig  extends WebMvcConfigurerAdapter implements WebSocketConfigurer {

    @Autowired
    MyWebSocketHandler handler;

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

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

}

HandShake :

package com.interceptor;

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 javax.servlet.http.HttpSession;
import java.util.Map;

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

    public void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Exception e) {

    }
}

MyWebSocketHandler :

package com.handler;


import com.entity.Message;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@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 {
        System.out.println("------->connection!!!!");
        Long uid = (Long) session.getAttributes().get("uid");
        if (userSocketSessionMap.get(uid) == null) {
            userSocketSessionMap.put(uid, session);
        }
    }

    public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> webSocketMessage) throws Exception {
        if(webSocketMessage.getPayloadLength()==0)return;
        Message msg = new Gson().fromJson(webSocketMessage.getPayload().toString(),Message.class);  //转换格式
        msg.setDate(new Date());
        System.out.println(msg);
        sendMessageToUser(msg.getTo(),new TextMessage(new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create().toJson(msg)));
    }

    public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throws Exception {

    }

    public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception {

    }

    public boolean supportsPartialMessages() {
        return false;
    }
    public void sendMessageToUser(Long uid,TextMessage textMessage) throws IOException{
        WebSocketSession session = userSocketSessionMap.get(uid);
        if(session!=null&&session.isOpen()){
            session.sendMessage(textMessage);
        }
    }
}

还有两个实体类:
User:

package com.entity;

public class User {
    private Long id;

    private String name;

    private String password;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

Message:

package com.entity;

import java.util.Date;

public class Message {

    //发送者
    public Long from;
    //发送者名称
    public String fromName;
    //接收者
    public Long to;
    //发送的文本
    public String text;
    //发送日期
    public Date date;

    public Long getFrom() {
        return from;
    }

    public void setFrom(Long from) {
        this.from = from;
    }

    public Long getTo() {
        return to;
    }

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

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public String getFromName() {
        return fromName;
    }

    public void setFromName(String fromName) {
        this.fromName = fromName;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    @Override
    public String toString() {
        return "Message{" +
                "from=" + from +
                ", fromName='" + fromName + '\'' +
                ", to=" + to +
                ", text='" + text + '\'' +
                ", date=" + date +
                '}';
    }
}

附上一张项目分层的截图:
这里写图片描述
pom.xml:

<dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <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>

其他的配置应该都没问题了;

简单描述一下整个过程,以后再看的时候能快速理解,

登录页面 —> controller ,controller中执行login方法,在session中存了两个值 uid 和 name
再跳转到talk.jsp , 在talk.jsp中,获取session中的值,通过
websocket = new WebSocket("ws://" + path + "/ws?uid="+uid); 来建立websocket连接,
这个路径的配置在 WebSocketConfig 中
registry.addHandler(handler, "/ws").addInterceptors(new HandShake()); 注册一个处理类的路径,并且添加一个拦截器 new HandShake(); 拦截器中会根据判断来断开连接,或继续连接;
连接成功后,进入 MyWebSocketHandler 中的 afterConnectionEstablished ,这样一个连接就建立完成; 数据的发送 在handleMessage方法中,前端接收onmessage ; 指定的发送,在前端页面已经写死,
可以根据自己需求更改;

猜你喜欢

转载自blog.csdn.net/naihe0420/article/details/78224485