java 实现websocket的两种方式实例详解

一、介绍

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

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

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

二、方式一:tomcat

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

 服务器端代码

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<String, WebSocket> clients = new ConcurrentHashMap<String, WebSocket>();

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<String, WebSocket> getClients() {

return clients;

}

}

客户端js

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整合

WebSocketConfig.java

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

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类是一个工具类,两个常量。

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<String, Object> 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

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

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<WebSocketSession> users;// 这个会出现性能问题,最好用Map来存储,key用userid

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

static {

users = new ArrayList<WebSocketSession>();

}

/**

* 连接成功时候,会触发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类的扫描,并且增加

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

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

<a target="_blank" href="http://www.springframework.org/schema/websocket/spring-websocket-4.1.xsd" rel="external nofollow" >http://www.springframework.org/schema/websocket/spring-websocket-4.1.xsd</a>

客户端

<script type="text/javascript"

src="http://localhost:8080/Bank/js/sockjs-0.3.min.js"></script>

<script>

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("(<font color='red'>" + evnt.data + "</font>)")

};

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("连接失败!");

}

});

</script>

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

总结

以上所述是小编给大家介绍的java 实现websocket的两种方式实例详解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!

以上是 java 实现websocket的两种方式实例详解 的全部内容, 来源链接: utcz.com/z/313108.html

回到顶部