WebSocket整合Springboot

WebSocket+Springboot

1.1 pom 文件的依赖和插件

 
        org.springframework.boot
        spring-boot-starter-parent
        1.5.9.RELEASE
   

   
       
            junit
            junit
            3.8.1
            test
       
       
       
            javax.servlet
            javax.servlet-api
            3.1.0
       
       
            org.glassfish.web
            jsp
            2.2
       
       
       
            javax.websocket
            javax.websocket-api
            1.1
            provided
       
       
       
            net.sf.json-lib
            json-lib
            2.4
       
       
            org.springframework.boot
            spring-boot-starter-web
           
               
                    org.springframework.boot
                    spring-boot-starter-tomcat
               
           
       
       
       
            org.springframework
            spring-websocket
       
      
       
            ch.qos.logback
            logback-core
       
       
            ch.qos.logback
            logback-classic
       
   
   
        websocketspring

       
           
                org.springframework.boot
                spring-boot-maven-plugin
           
       
   

我们提供的服务有:成都网站制作、网站建设、外贸网站建设、微信公众号开发、网站优化、网站认证、滕州ssl等。为上1000+企事业单位解决了网站和推广的问题。提供周到的售前咨询和贴心的售后服务,是有科学管理、有技术的滕州网站制作公司

1.2 WebSocket 的配置文件

用于启动 websocket,注入处理器和拦截器

/**
 * Created by jackiechan on 2018/2/5/下午4:05
 */
@Configuration //声明为配置文件
@EnableWebSocket//启用 websocket
public class WebSocketConfig implements WebSocketConfigurer {
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
        System.out.println("初始化路径拦截");//指定所有/websocket开头的路径会被 websocket 拦截,设置处理器和拦截器
        webSocketHandlerRegistry.addHandler(chatMessageHandler(),"/websocket/*").addInterceptors(new ChatHandshakeInterceptor());
    }

    /**
     * 创建处理器
     * @return
     */
    @Bean
    public TextWebSocketHandler chatMessageHandler(){
        System.out.println("创建 handler");
        return new ChatMessageHandler();
    }
}

1.3 ChatHandshakeInterceptor拦截器

用于每次 websocket 在握手之前进行拦截,可以在内部进行校验


/**
 * Created by jackiechan on 2018/2/5/下午4:16
 *
 * WebSocket握手请求的拦截器. 检查握手请求和响应, WebSocketHandler传递属性
 */
public class ChatHandshakeInterceptor extends HttpSessionHandshakeInterceptor {
    /**
     * 在握手之前执行该方法, 继续握手返回true, 中断握手返回false. 通过attributes参数设置WebSocketSession的属性
     * @param request
     * @param response
     * @param wsHandler
     * @param attributes
     * @return
     * @throws Exception
     */
    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
                                   Map<String, Object> attributes) throws Exception {
        //为了方便区分来源,在此以用户的名字来区分,名字我们通过要求用输入进行传递,所以在这里先从请求中获取到用户输入的名字,因为是使用的rest 风格,所以规定路径的最后一个字符串是名字
        System.out.println("握手之前");
        String s = request.getURI().toString();
        String s1 = s.substring(s.lastIndexOf("/") + 1);
        attributes.put(Constants.WEBSOCKET_USERNAME, s1);//给当前连接设置属性

        return super.beforeHandshake(request, response, wsHandler, attributes);
    }

    /**
     * 在握手之后执行该方法. 无论是否握手成功都指明了响应状态码和相应头.
     * @param request
     * @param response
     * @param wsHandler
     * @param ex
     */
    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
                               Exception ex) {
        System.out.println("After Handshake");
        super.afterHandshake(request, response, wsHandler, ex);
    }

}

1.4 ChatMessageHandler消息处理器

用于收到消息的时候处理消息


/**
 * Created by jackiechan on 2018/2/5/下午4:11
 * 文本消息的处理器
 */
public class ChatMessageHandler extends TextWebSocketHandler {

    private static final Map<String,WebSocketSession> allClients;//用于缓存所有的用户和连接之间的关系
    private static Logger logger = Logger.getLogger(ChatMessageHandler.class);

    static {
        allClients = new ConcurrentHashMap();//初始化连接
    }

    /**
     * 当和用户成功建立连接的时候会调用此方法,在此方法内部应该保存连接
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        System.out.println("建立连接成功");
        String name = (String) session.getAttributes().get(Constants.WEBSOCKET_USERNAME);//将在拦截器中保存的用户的名字取出来,然后作为 key 存到 map
        if (name != null) {
            allClients.put(name, session);//保存当前的连接和用户之间的关系
        }
        // 这块会实现自己业务,比如,当用户登录后,会把离线消息推送给用户

    }

    /**
     * 收到消息的时候会触发该方法
     * @param session 发送消息的用户的 session
     * @param message  发送的内容
     * @throws Exception
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        //此处请根据自己的具体业务逻辑做处理
        JSONObject jsonObject= JSONObject.fromObject(new String(message.asBytes()));//将用户发送的消息转换为 json,实际开发中请根据自己的需求处理
        String toName = jsonObject.getString("toName");//获取数据中的收消息人的名字
        String content = jsonObject.getString("content");//获取到发送的内容
        String fromName = (String) session.getAttributes().get(Constants.WEBSOCKET_USERNAME);//获取当前发送消息的人的名字
        content = "收到来自:" +fromName+ "的消息,内容是:" + content;
        //拼接内容转发给接收者,实际开发中请参考自己的需求做处理
        TextMessage textMessage = new TextMessage(content);//将内容转换为 TextMessage
        sendMessageToUser(toName,textMessage);// 发送给指定的用户
        //sendMessageToUsers(message);//给所有人发送
        //super.handleTextMessage(session, message);
    }

    /**
     * 给某个用户发送消息
     *
     * @param userName
     * @param message
     */
    public void sendMessageToUser(String userName, TextMessage message) {
        WebSocketSession webSocketSession = allClients.get(userName);//根据接收方的名字找到对应的连接
        if (webSocketSession != null&& webSocketSession.isOpen()) {//如果没有离线,如果离线,请根据实际业务需求来处理,可能会需要保存离线消息
            try {
                webSocketSession.sendMessage(message);//发送消息
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 给所有在线用户发送消息,此处以文本消息为例子
     *
     * @param message
     */
    public void sendMessageToUsers(TextMessage message) {
        for (Map.Entry<String, WebSocketSession> webSocketSessionEntry : allClients.entrySet()) {//获取所有的连接

            WebSocketSession session = webSocketSessionEntry.getValue();//找到每个连接
            if (session != null&& session.isOpen()) {
                try {
                    session.sendMessage(message);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 出现异常的时候
     * @param session
     * @param exception
     * @throws Exception
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        String name = (String) session.getAttributes().get(Constants.WEBSOCKET_USERNAME);
        if (session.isOpen()) {
            session.close();
        }
        logger.debug("连接关闭");
        allClients.remove(name);//移除连接
    }

    /**
     * 连接关闭后
     * @param session
     * @param closeStatus
     * @throws Exception
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
        logger.debug("连接关闭");
        String name = (String) session.getAttributes().get(Constants.WEBSOCKET_USERNAME);//找到用户对应的连接
        allClients.remove(name);//移除
    }

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

}

1.5 springboot 启动类

注意此类最好放在根包下


/**
 * Created by jackiechan on 2018/2/5/下午4:34
 */
@SpringBootApplication
@Configuration
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);//   spingboot    }
    }
}

1.6 web 方式启动项的配置类


/**
 * Created by jackiechan on 2018/2/5/下午4:34
 用于将项目打包成 war 包后发布
 */
public class SpringBootStartApplication extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder)
    {
        return builder.sources(App.class);
    }
}

1.7 html

与非 springboot 的方式内容一致

html>
lang="en">

    charset="UTF-8">
    </em></strong><em>Title</em><strong><em>
    type="text/javascript">
        var websocket = null;
        function abc() {

            //var username = localStorage.getItem("name");
            var username=document.getElementById("me").value;
            //判断当前浏览器是否支持WebSocket
            if ('WebSocket' in window) {
                websocket = new WebSocket("ws://" + document.location.host + "/websocket/"+username);
            } else {
                alert('当前浏览器 Not support websocket')
            }

            //连接发生错误的回调方法
            websocket.onerror = function() {
                setMessageInnerHTML("WebSocket连接发生错误");
            };

            //连接成功建立的回调方法
            websocket.onopen = function() {
                setMessageInnerHTML("WebSocket连接成功");
            }

            //接收到消息的回调方法
            websocket.onmessage = function(event) {
                setMessageInnerHTML(event.data);
            }

            //连接关闭的回调方法
            websocket.onclose = function() {
                setMessageInnerHTML("WebSocket连接关闭");
            }

            //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
            window.onbeforeunload = function() {
                closeWebSocket();
            }
        }

        /**
         * 发送消息
         */
        function sendmessage() {
            var toName=document.getElementById("to").value;
            if (websocket!=null) {
                var content=document.getElementById("content").value;

                var message='{"toName":"'+toName+'","content":"'+content+'"}';//将发送的内容拼接为 json 字符串,服务端用于解析好处理
                websocket.send(message);
            }
        }

        //关闭WebSocket连接
        function closeWebSocket() {
            if (websocket!=null) {

                websocket.close();
            }
        }
        function setMessageInnerHTML(data) {
            document.getElementById("neirong").innerHTML = data;
        }
   


用户名: type="text" id="me" /> onclick="abc()"> 连接


接收者: type="text" id="to" />

内容: type="text" id="content" />

onclick="sendmessage()">发送







id="neirong">

1.8 启动测试

WebSocket 整合 Springboot


分享文章:WebSocket整合Springboot
文章来源:http://pwwzsj.com/article/googds.html