SpringMVC+WebSocket+H5 Notification实例

Java 发表评论


传统的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.csdn.net/download/lishengko/9998130

发表评论

电子邮件地址不会被公开。 必填项已用*标注

昵称 *