SpringMVC+WebSocket+H5 Notification实例

本文介绍如何使用WebSocket实现实时双向通信,包括SpringMVC、Tomcat配置及具体实现代码,展示了客户端与服务器端交互的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传统的HTTP协议是被动的,单项的即服务器传递信息给客户端,每次发送信息都需要封装HTTP协议中的Headers等相关信息。实时性消息较高的应用场景瓶颈非常明显如聊天室,无法主动获取客户端发送的信息,每次传输数据都需要发送一个完整的HTTP请求,数据传输效率低。
WebSocket其实就是一套新的协议,可以实现Socket编程效果,初次连接的时候初始化一次,只要连接不关闭便可以实现客户端和服务器的实时数据传递。
WebSocket协议是基于HTTP即浏览器的一套新的编程接口,客户端与服务器的连接通过JavaScript编程,页面关闭后连接便失效了,刷新页面会先关闭当前的连接再建立新的连接。

开发工具:
SpringMVC4.0+(spring-websocket包,支持WebSocket编程)
Tomcat 7.0+ (支持WebSocket协议)

实例使用的是SpringMVC4.15+Tomcat7.0.76+JDK1.8

核心代码:
WebSocketInterceptor 拦截器,每次连接时触发。
WebSocketConfig 配置文件,WebSocket实例化。
SocketHandler 业务逻辑处理。

public class WebSocketInterceptor implements HandshakeInterceptor {

    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler handler, Map<String, Object> map) throws Exception {
        ServletServerHttpRequest serverHttpRequest = (ServletServerHttpRequest) request;这里写代码片
        String[] str = serverHttpRequest.getServletRequest().getParameterMap().get("id");
        map.put("id", str[0]);
        return true;
    }

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

    }
}ide
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler handler, Map<String, Object> map) throws Exception {
        ServletServerHttpRequest serverHttpRequest = (ServletServerHttpRequest) request;
        String[] str = serverHttpRequest.getServletRequest().getParameterMap().get("id");
        map.put("id", str[0]);
        return true;
    }

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

    }
}


@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(myHandler(), "/socketHandler").addInterceptors(new WebSocketInterceptor()).setAllowedOrigins("*");
    }

    //@Bean
    public WebSocketHandler myHandler() {
        return new SocketHandler();
    }

}

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(myHandler(), "/socketHandler").addInterceptors(new WebSocketInterceptor()).setAllowedOrigins("*");
    }

    //@Bean
    public WebSocketHandler myHandler() {
        return new SocketHandler();
    }

}


@Service
public class SocketHandler extends TextWebSocketHandler {
    //在线用户列表(适用于单用户多点)
    private static final Map<Integer, List<WebSocketSession>> users;

    static {
        users = new HashMap<>();
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        System.out.println("成功建立连接");
        Integer userId = getClientId(session);
        List<WebSocketSession> list = users.get(userId);
        if (null == list){
            list = new ArrayList<>();
            list.add(session);
            users.put(userId, list);
        } 
        else
            list.add(session);
    }

    /***
     * 接收客户端信息
     */
    @Override
    public void handleTextMessage(WebSocketSession session, TextMessage message) {
        System.out.println(message.getPayload());
    }

    /**
     * 发送信息给指定用户
     * @param userloginid 用户标识
     * @param message
     * @return
     */
    public void sendMessageToUser(Integer userloginid, TextMessage message) {
        if (users.get(userloginid) == null) 
            return;
        List<WebSocketSession> list = users.get(userloginid);
        for(int i=0;i<list.size();i++){
            WebSocketSession session = list.get(i);
            if (!session.isOpen()) 
                continue;
            try {
                session.sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 广播信息
     * @param userloginid 用户标识
     * @param message
     * @return
     */
    public void sendMessageToAllUser(Integer userloginid,TextMessage message) {
        Set<Integer> clientIds = users.keySet();
        for (Integer clientId : clientIds) {
            if(clientId != userloginid)
                sendMessageToUser(clientId,message);
        }
    }

    /**
     * 广播信息
     * @param message
     * @return
     */
    public void sendMessageToAllUsers(TextMessage message) {
        Set<Integer> clientIds = users.keySet();
        for (Integer clientId : clientIds) {
            sendMessageToUser(clientId,message);
        }
    }

    /***
     * 关闭连接
     * @param id
     * @param session
     */
    public void remove(int id,WebSocketSession session){
        if (users.get(id) == null) 
            return;
        List<WebSocketSession> list = users.get(id);
        Optional<WebSocketSession> optional = list.stream().filter(m->m.equals(session)).findFirst();
        if(optional.isPresent())
            list.remove(optional.get());
        if(null == list || list.size()==0)
            users.remove(id);
    }

    /***
     * 出错是执行,关闭浏览器界面会执行该方法,并自动关闭session
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        if (session.isOpen()) {
            session.close();
        }
        remove(getClientId(session),session);
    }

    /***
     * 关闭session时执行
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        if (session.isOpen()) {
            session.close();
        }
        remove(getClientId(session),session);
    }

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

    /**
     * 获取用户标识
     * @param session
     * @return
     */
    private Integer getClientId(WebSocketSession session) {
        return Integer.parseInt(session.getAttributes().get("id").toString());
    }
}

HTML代码:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page isELIgnored="false"%> 
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head> 
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>WebSocket</title> 
</head> 
<body> 
    <button>socket连接</button>   
    <script src="${pageContext.request.contextPath}/js/jquery-2.1.1.js"></script>
    <script type="text/javascript">
      $(function() {
        $("button").click(function(){
            if (typeof WebSocket == 'undefined') 
                alert("浏览器不支持相关特性,请更换为谷歌,UC浏览器。")  
            else{
                //WebSocket客户端建立,生命周期为当前页面。
                var ws = new WebSocket("ws://localhost:8123/websocket/socketHandler?id=4")
                ws.onopen = function () {
                    console.log("onpen");
                    ws.send("客户端发送消息");
                }

                //页面关闭便会触发
                ws.onclose = function () {
                    console.log("onclose");
                }

                ws.onmessage = function (msg) {
                    console.log(msg.data);
                    var message = msg.data.split(",");
                    //浏览器支持Notification,并允许接收通知
                    if($.notificationHandler.requestPermission())
                    $.notificationHandler.showNotification('${pageContext.request.contextPath}/images/11.png',message[0],message[1]);
                }   
            }

        });
      })
    </script>
</body>


</html>

本实例中运用到了H5的Notification发送通知,相关代码已封装到JS文件里了,便不多叙述了。

下载地址:http://download.youkuaiyun.com/download/lishengko/9998130

WebSocket客户端和服务端实例源码 WebSocket ws实例 HTML5 用java实现的服务端 Websocket与服务器的正常通信 众所周知,Web 应用的交互过程通常是客户端通过浏览器发出一个请求,服务器端接收请求后进行处理并返回结果给客户端,客户端浏览器将信息呈现,这种机制对于信息变化不是特别频繁的应用尚可,但对于实时要求高、海量并发的应用来说显得捉襟见肘,尤其在当前业界移动互联网蓬勃发展的趋势下,高并发与用户实时响应是 Web 应用经常面临的问题,比如金融证券的实时信息,Web 导航应用中的地理位置获取,社交网络的实时消息推送等。 传统的请求-响应模式的 Web 开发在处理此类业务场景时,通常采用实时通讯方案,常见的是: 轮询,原理简单易懂,就是客户端通过一定的时间间隔以频繁请求的方式向服务器发送请求,来保持客户端和服务器端的数据同步。问题很明显,当客户端以固定频率向服务器端发送请求时,服务器端的数据可能并没有更新,带来很多无谓请求,浪费带宽,效率低下。 基于 Flash,AdobeFlash 通过自己的 Socket 实现完成数据交换,再利用 Flash 暴露出相应的接口为 JavaScript 调用,从而达到实时传输目的。此方式比轮询要高效,且因为 Flash 安装率高,应用场景比较广泛,但在移动互联网终端上 Flash 的支持并不好。IOS 系统中没有 Flash 的存在,在 Android 中虽然有 Flash 的支持,但实际的使用效果差强人意,且对移动设备的硬件配置要求较高。2012 年 Adobe 官方宣布不再支持 Android4.1+系统,宣告了 Flash 在移动终端上的死亡。 从上文可以看出,传统 Web 模式在处理高并发及实时性需求的时候,会遇到难以逾越的瓶颈,我们需要一种高效节能的双向通信机制来保证数据的实时传输。在此背景下,基于 HTML5 规范的、有 Web TCP 之称的 WebSocket 应运而生。 早期 HTML5 并没有形成业界统一的规范,各个浏览器和应用服务器厂商有着各异的类似实现,如 IBM 的 MQTT,Comet 开源框架等,直到 2014 年,HTML5 在 IBM、微软、Google 等巨头的推动和协作下终于尘埃落地,正式从草案落实为实际标准规范,各个应用服务器及浏览器厂商逐步开始统一,在 JavaEE7 中也实现了 WebSocket 协议,从而无论是客户端还是服务端的 WebSocket 都已完备,读者可以查阅HTML5 规范,熟悉新的 HTML 协议规范及 WebSocket 支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值