java websocket框架_java 实现websocket的两种方式

简单说明

1.两种方式,一种使用tomcat的websocket实现,一种使用spring的websocket

2.tomcat的方式需要tomcat 7.x,JEE7的支持。

3.spring与websocket整合需要spring 4.x,并且使用了socketjs,对不支持websocket的浏览器可以模拟websocket使用

方式一:tomcat

使用这种方式无需别的任何配置,只需服务端一个处理类,

服务器端代码

[java]

package com.Socket;

import java.io.IOException;

import java.util.Map;

import java.util.concurrent.ConcurrentHashMap;

import javax.websocket.*;

import javax.websocket.server.PathParam;

import javax.websocket.server.ServerEndpoint;

import net.sf.json.JSONObject;

@ServerEndpoint("/websocket/{username}")

public class WebSocket {

private static int onlineCount = 0;

private static Map clients = new ConcurrentHashMap();

private Session session;

private String username;

@OnOpen

public void onOpen(@PathParam("username") String username, Session session) throws IOException {

this.username = username;

this.session = session;

addOnlineCount();

clients.put(username, this);

System.out.println("已连接");

}

@OnClose

public void onClose() throws IOException {

clients.remove(username);

subOnlineCount();

}

@OnMessage

public void onMessage(String message) throws IOException {

JSONObject jsonTo = JSONObject.fromObject(message);

if (!jsonTo.get("To").equals("All")){

sendMessageTo("给一个人", jsonTo.get("To").toString());

}else{

sendMessageAll("给所有人");

}

}

@OnError

public void onError(Session session, Throwable error) {

error.printStackTrace();

}

public void sendMessageTo(String message, String To) throws IOException {

// session.getBasicRemote().sendText(message);

//session.getAsyncRemote().sendText(message);

for (WebSocket item : clients.values()) {

if (item.username.equals(To) )

item.session.getAsyncRemote().sendText(message);

}

}

public void sendMessageAll(String message) throws IOException {

for (WebSocket item : clients.values()) {

item.session.getAsyncRemote().sendText(message);

}

}

public static synchronized int getOnlineCount() {

return onlineCount;

}

public static synchronized void addOnlineCount() {

WebSocket.onlineCount++;

}

public static synchronized void subOnlineCount() {

WebSocket.onlineCount--;

}

public static synchronized Map getClients() {

return clients;

}

}

客户端js

[javascript]

var websocket = null;

var username = localStorage.getItem("name");

//判断当前浏览器是否支持WebSocket

if ('WebSocket' in window) {

websocket = new WebSocket("ws://" + document.location.host + "/WebChat/websocket/" + username + "/"+ _img);

} 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();

}

//关闭WebSocket连接

function closeWebSocket() {

websocket.close();

}

发送消息只需要使用websocket.send("发送消息"),就可以触发服务端的onMessage()方法,当连接时,触发服务器端onOpen()方法,此时也可以调用发送消息的方法去发送消息。关闭websocket时,触发服务器端onclose()方法,此时也可以发送消息,但是不能发送给自己,因为自己的已经关闭了连接,但是可以发送给其他人。

方法二:spring整合

此方式基于spring mvc框架,相关配置可以看我的相关博客文章

WebSocketConfig.java

这个类是配置类,所以需要在spring mvc配置文件中加入对这个类的扫描,第一个addHandler是对正常连接的配置,第二个是如果浏览器不支持websocket,使用socketjs模拟websocket的连接。

[java]

package com.websocket;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

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 org.springframework.web.socket.handler.TextWebSocketHandler;

@Configuration

@EnableWebSocket

public class WebSocketConfig implements WebSocketConfigurer {

@Override

public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {

registry.addHandler(chatMessageHandler(),"/webSocketServer").addInterceptors(new ChatHandshakeInterceptor());

registry.addHandler(chatMessageHandler(), "/sockjs/webSocketServer").addInterceptors(new ChatHandshakeInterceptor()).withSockJS();

}

@Bean

public TextWebSocketHandler chatMessageHandler(){

return new ChatMessageHandler();

}

}

ChatHandshakeInterceptor.java

这个类的作用就是在连接成功前和成功后增加一些额外的功能,Constants.java类是一个工具类,两个常量。

[java]

package com.websocket;

import java.util.Map;

import org.apache.shiro.SecurityUtils;

import org.springframework.http.server.ServerHttpRequest;

import org.springframework.http.server.ServerHttpResponse;

import org.springframework.web.socket.WebSocketHandler;

import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;

public class ChatHandshakeInterceptor extends HttpSessionHandshakeInterceptor {

@Override

public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,

Map attributes) throws Exception {

System.out.println("Before Handshake");

/*

* if (request instanceof ServletServerHttpRequest) {

* ServletServerHttpRequest servletRequest = (ServletServerHttpRequest)

* request; HttpSession session =

* servletRequest.getServletRequest().getSession(false); if (session !=

* null) { //使用userName区分WebSocketHandler,以便定向发送消息 String userName =

* (String) session.getAttribute(Constants.SESSION_USERNAME); if

* (userName==null) { userName="default-system"; }

* attributes.put(Constants.WEBSOCKET_USERNAME,userName);

*

* } }

*/

//使用userName区分WebSocketHandler,以便定向发送消息(使用shiro获取session,或是使用上面的方式)

String userName = (String) SecurityUtils.getSubject().getSession().getAttribute(Constants.SESSION_USERNAME);

if (userName == null) {

userName = "default-system";

}

attributes.put(Constants.WEBSOCKET_USERNAME, userName);

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

}

@Override

public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,

Exception ex) {

System.out.println("After Handshake");

super.afterHandshake(request, response, wsHandler, ex);

}

}

ChatMessageHandler.java

这个类是对消息的一些处理,比如是发给一个人,还是发给所有人,并且前端连接时触发的一些动作

[java]

package com.websocket;

import java.io.IOException;

import java.util.ArrayList;

import org.apache.log4j.Logger;

import org.springframework.web.socket.CloseStatus;

import org.springframework.web.socket.TextMessage;

import org.springframework.web.socket.WebSocketSession;

import org.springframework.web.socket.handler.TextWebSocketHandler;

public class ChatMessageHandler extends TextWebSocketHandler {

private static final ArrayList users;// 这个会出现性能问题,最好用Map来存储,key用userid

private static Logger logger = Logger.getLogger(ChatMessageHandler.class);

static {

users = new ArrayList();

}

/**

* 连接成功时候,会触发UI上onopen方法

*/

@Override

public void afterConnectionEstablished(WebSocketSession session) throws Exception {

System.out.println("connect to the websocket success......");

users.add(session);

// 这块会实现自己业务,比如,当用户登录后,会把离线消息推送给用户

// TextMessage returnMessage = new TextMessage("你将收到的离线");

// session.sendMessage(returnMessage);

}

/**

* 在UI在用js调用websocket.send()时候,会调用该方法

*/

@Override

protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {

sendMessageToUsers(message);

//super.handleTextMessage(session, message);

}

/**

* 给某个用户发送消息

*

* @param userName

* @param message

*/

public void sendMessageToUser(String userName, TextMessage message) {

for (WebSocketSession user : users) {

if (user.getAttributes().get(Constants.WEBSOCKET_USERNAME).equals(userName)) {

try {

if (user.isOpen()) {

user.sendMessage(message);

}

} catch (IOException e) {

e.printStackTrace();

}

break;

}

}

}

/**

* 给所有在线用户发送消息

*

* @param message

*/

public void sendMessageToUsers(TextMessage message) {

for (WebSocketSession user : users) {

try {

if (user.isOpen()) {

user.sendMessage(message);

}

} catch (IOException e) {

e.printStackTrace();

}

}

}

@Override

public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {

if (session.isOpen()) {

session.close();

}

logger.debug("websocket connection closed......");

users.remove(session);

}

@Override

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

logger.debug("websocket connection closed......");

users.remove(session);

}

@Override

public boolean supportsPartialMessages() {

return false;

}

}

spring-mvc.xml

正常的配置文件,同时需要增加对WebSocketConfig.java类的扫描,并且增加

[html]

xmlns:websocket="http://www.springframework.org/schema/websocket"

http://www.springframework.org/schema/websocket

http://www.springframework.org/schema/websocket/spring-websocket-4.1.xsd

客户端

[html]

var websocket;

if ('WebSocket' in window) {

websocket = new WebSocket("ws://" + document.location.host + "/Bank/webSocketServer");

} else if ('MozWebSocket' in window) {

websocket = new MozWebSocket("ws://" + document.location.host + "/Bank/webSocketServer");

} else {

websocket = new SockJS("http://" + document.location.host + "/Bank/sockjs/webSocketServer");

}

websocket.onopen = function(evnt) {};

websocket.onmessage = function(evnt) {

$("#test").html("(" + evnt.data + ")")

};

websocket.onerror = function(evnt) {};

websocket.onclose = function(evnt) {}

$('#btn').on('click', function() {

if (websocket.readyState == websocket.OPEN) {

var msg = $('#id').val();

//调用后台handleTextMessage方法

websocket.send(msg);

} else {

alert("连接失败!");

}

});

注意导入socketjs时要使用地址全称,并且连接使用的是http而不是websocket的ws

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值