websocket

最近因为业务需求,需要进行长连接开发,所以对websocket进行了了解,入坑好几天,下面是一点点总结。

websocket后端java的开发主要有两种方式,一个基于javax的开发,一个是基于spring框架的开发。我这个使用的是基于spring框架进行开发的。话不多说,直接上代码。

首先需要导入依赖:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-websocket</artifactId>
    <version>${spring.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-messaging</artifactId>
    <version>${spring.version}</version>
</dependency>

首先是websocket的配置类:

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {


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

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

}

编写websocket的拦截器

public class WebSocketInterceptor implements HandshakeInterceptor {

    final Logger logger = Logger.getLogger(WebSocketInterceptor.class);
    /**
     * 当客户端与服务器端握手之前之前执行的方法
     * 取出当前存在session的用户信息将openid,封装到WebSocket对象中的map中;
     * 由Handler处理器中获取openid
     * @return
     */
    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
                                   WebSocketHandler webSocketHandler, Map<String, Object> map) throws Exception {
        ServletServerHttpRequest serverHttpRequest = (ServletServerHttpRequest) request;
        HttpSession session = serverHttpRequest.getServletRequest().getSession();
        HttpServletResponse httpServletResponse = ((ServletServerHttpResponse)response).getServletResponse();
        String openId = ((ServletServerHttpRequest) request).getServletRequest().getParameter("openId");
        logger.info("openid is:" + openId);
        logger.info(JSONObject.toJSONString(((ServletServerHttpRequest) request).getServletRequest().getParameterMap()));
        map.put("openId", openId);
        System.out.println(map.get("openId") + " $$$$$$$$");
        ((ServletServerHttpRequest) request).getServletRequest().getSession().setAttribute("openId",openId);
        if (StringUtils.isNotEmpty(((ServletServerHttpRequest) request).getServletRequest().
                getHeader("Sec-WebSocket-Protocol"))) {
            httpServletResponse.addHeader("Sec-WebSocket-Protocol",
                    ((ServletServerHttpRequest) request).getServletRequest().getHeader("Sec-WebSocket-Protocol"));
        }
        return true;
    }

    //与服务器websoket建立握手之后执行的方法
    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response,
                               WebSocketHandler webSocketHandler, @Nullable Exception e) {
    }
}

最后是websocket的各种功能实现

public class MyHandler extends TextWebSocketHandler {

    //在线用户列表
    private static final Map<String, WebSocketSession> users;
    private static final String OPEN_ID = "openId"; //用户标识
    //类加载初始化一个map集合,存放用户的websocket对象
    static{
        users = new HashMap<String, WebSocketSession>();
    }

    /**
     * 获取用户标识,获取websocekt对象的map集合
     * @param session
     * @return
     */
    private String getClientId(WebSocketSession session) {
        try {
            //获取存入websocket的openId
            String openId = (String) session.getAttributes().get(OPEN_ID);
            return openId;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 成功建立连接触发的方法,
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        //取出拦截器放入的openid,为当前的websoket绑定用户到map
        String openId = getClientId(session);
        System.out.println(openId+":链接获得id");
        if (openId != null) {
            users.put(openId, session);
            session.sendMessage(new TextMessage("成功建立socket连接"));
            System.out.println(openId +"%%%%%%%%%%%%%%");
            System.out.println(session + "********");
        }
    }

    /**
     * 当接收到客户端浏览器后接收的方法
     */
    @Override
    public void handleTextMessage(WebSocketSession session, TextMessage message) {
        System.out.println(message.getPayload());
        WebSocketMessage message1 = new TextMessage("server:"+message);
        try {
            session.sendMessage(message1);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 发送信息给指定用户
     * @param openid
     * @param message
     * @return
     * map中根据用户的id获取对应得websoket,发送信息
     */
    public boolean sendMessageToUser(String openid, TextMessage message) {
        //获取当前的
        if (users.get(openid) == null) return false;
        WebSocketSession session = users.get(openid);
        System.out.println("sendMessage:" + session);
        if (!session.isOpen()) return false;
        try {
            session.sendMessage(message);
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 广播信息(发送给所有人)
     * @param message
     * @return
     * 遍历出map中所有的websocket发送在线消息
     */
    public boolean sendMessageToAllUsers(TextMessage message) {
        boolean allSendSuccess = true;
        Set<String> openids = users.keySet();
        WebSocketSession session = null;
        for (String openid : openids) {
            try {
                session = users.get(openid);
                if (session.isOpen()) {
                    session.sendMessage(message);
                }
            } catch (IOException e) {
                e.printStackTrace();
                allSendSuccess = false;
            }
        }

        return  allSendSuccess;
    }

    /**
     * 当链接发生异常后触发的方法,关闭出错会话的连接,和删除在Map集合中的记录
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        //判断当前的链接是否在继续,关闭连接
        if (session.getAttributes().get(OPEN_ID) == null) {
            session.close();
        }
        System.out.println("连接出错");
        users.remove(getClientId(session));

    }

    /**
     * 当链接关闭后触发的方法,连接已关闭,移除在Map集合中的记录。
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {

        System.out.println("连接已关闭:" + status); //当前的状态码,并删除存储在map中的websocket的链接对象
        users.remove(getClientId(session));
    }

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

可以写一个前端的html页面进行测试,这里也附上一个吧

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script>
</head>
<body>

</body>
<script type="application/javascript">

    var host = "localhost:9100";
    var websocket;
    if ('WebSocket' in window) {
        websocket = new WebSocket("ws://"
            + host + "/webSocketServer?openId=oo41c5ZrJE8hf_dVKFZDnnkq5Na4", "a", {debug:true, maxReconnectAttempts:4});
    } else if ('MozWebSocket' in window) {
        websocket = new MozWebSocket("ws://" + host
            + "/webSocketServer");
    } else {
        websocket = new SockJS("http://" + host
            + "/sockjs/webSocketServer");
    }
    websocket.onopen = function(evnt) {
        console.log("websocket连接上");
    };
    websocket.onmessage = function(evnt) {
        messageHandler(evnt.data);
    };
    websocket.onerror = function(evnt) {
        console.log("websocket错误");
    };
    websocket.onclose = function(evnt) {
        console.log("websocket关闭");
    }
</script>
</html>
水平有限,如果有什么错误之处,希望路过的大神基于指正,谢谢!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值