一、服务端
<!--即时通讯服务端-->
<dependency>
<!-- websocket -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<!-- fastjson -->
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.4.4</version>
</dependency>
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
/**
* 注入一个ServerEndpointExporter,该Bean会自动注册使用@ServerEndpoint注解申明的websocket endpoint
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class WebSocketMapUtil {
public static ConcurrentMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
public static void put(String key, WebSocketServer webSocketServer){
webSocketMap.put(key, webSocketServer);
}
public static WebSocketServer get(String key){
return webSocketMap.get(key);
}
public static void remove(String key){
webSocketMap.remove(key);
}
public static Collection<WebSocketServer> getValues(){
return webSocketMap.values();
}
}
import java.io.IOException;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import cn.hutool.json.JSONObject;
import org.springframework.stereotype.Component;
@Component
@ServerEndpoint(value = "/websocket/service")
public class WebSocketServer {
private Session session;
/**
* 连接建立后触发的方法
*/
@OnOpen
public void onOpen(Session session) {
this.session = session;
WebSocketMapUtil.put(session.getId(), this);
}
/**
*连接关闭后触发的方法
*/
@OnClose
public void onClose() {
//从map中删除
WebSocketMapUtil.remove(session.getId());
}
/**
*接收到客户端消息时触发的方法
*/
@OnMessage
public void onMessage(String params, Session session) throws Exception {
//获取服务端到客户端的通道
WebSocketServer myWebSocket = WebSocketMapUtil.get(session.getId());
String result = "收到来自" + session.getId() + "的消息" + params;
//返回消息给Web Socket客户端(浏览器)
myWebSocket.sendMessage(1,"成功!", result);
}
public void sendMessage(int code, String msg, Object data) throws IOException {
JSONObject result = new JSONObject();
result.put("code", code);
result.put("msg", msg);
result.put("data", data);
this.session.getBasicRemote().sendText(result.toString());
}
/**
* 向指定客户端发送消息
* @param uid 客户端id
*/
public synchronized void send(String uid){
try {
WebSocketServer myWebSocket = WebSocketMapUtil.get(uid);
myWebSocket.sendMessage(1,"ok","null");
}catch (Exception e){
e.getMessage();
}
}
}
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@RequestMapping("/web/socket")
public class WebSocketController {
@Resource
private WebSocketServer myWebSocket;
/**
* 向客户端发送消息
* @param uid 客户端连接id
* @return
*/
@GetMapping("/send")
public String send(String uid){
myWebSocket.send(uid);
return "OK";
}
}
分别引入对应的类
二、 客户端
创建index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>即时通讯</title>
</head>
<body>
<input id="text" type="text" />
<button onclick="send()">Send</button>
<button onclick="closeWebSocket()">Close</button>
<div id="message"></div>
</body>
<script type="text/javascript">
var websocket = null;
//判断当前浏览器是否支持WebSocket, 主要此处要更换为自己的地址
if ('WebSocket' in window) {
// websocket = new WebSocket("即时通讯协议://服务器:服务端端口/服务类的路由");
websocket = new WebSocket("ws://127.0.0.1:8080/websocket/service");
} else {
alert('Not support websocket')
}
//连接发生错误的回调方法
websocket.onerror = function() {
setMessageInnerHTML("error");
};
//连接成功建立的回调方法
websocket.onopen = function(event) {
setMessageInnerHTML("连接成功");
}
//接收到消息的回调方法
websocket.onmessage = function(event) {
setMessageInnerHTML(event.data);
}
//连接关闭的回调方法
websocket.onclose = function() {
setMessageInnerHTML("关闭连接");
}
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function() {
websocket.close();
}
//将消息显示在网页上
function setMessageInnerHTML(innerHTML) {
document.getElementById('message').innerHTML += innerHTML + '
';
}
//关闭连接
function closeWebSocket() {
websocket.close();
}
//发送消息
function send() {
var message = document.getElementById('text').value;
websocket.send(message);
}
</script>
</html>
三、测试
调用控制器类的接口 传入指定客户端id即可对指定客户端发送消息:
<!--即时通讯客户端-->
<dependency>
<groupId>org.java-websocket</groupId>
<artifactId>Java-WebSocket</artifactId>
<version>1.3.8</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>1.7.25</version>
</dependency>
<!--轻量级别maven工程-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.6</version>
</dependency>
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.handshake.ServerHandshake;
import org.springframework.stereotype.Component;
import java.net.URI;
import java.net.URISyntaxException;
@Component
public class WsClient {
/**
* 获取客户端连接实例
* @param uri
* @return
*/
public WebSocketClient getClient(String uri) {
try {
//创建客户端连接对象
WebSocketClient client = new WebSocketClient(new URI(uri), new Draft_6455()) {
/**
* 建立连接调用
* @param serverHandshake
*/
@Override
public void onOpen(ServerHandshake serverHandshake) {
System.out.println("建立连接");
}
/**
* 收到服务端消息调用
* @param s
*/
@Override
public void onMessage(String s) {
System.out.println("收到来自服务端的消息:" + s);
}
/**
* 断开连接调用
*/
@Override
public void onClose(int i, String j, boolean k) {
System.out.println("关闭连接:::" + "i = " + i + ":::j = " + j + ":::k = " + k);
}
/**
* 连接报错调用
* @param e
*/
@Override
public void onError(Exception e) {
System.out.println("报错了:::" + e.getMessage());
}
};
//请求与服务端建立连接
client.connect();
//判断连接状态,0为请求中 1为已建立 其它值都是建立失败
while (client.getReadyState().ordinal() == 0) {
try {
Thread.sleep(200);
} catch (Exception e) {
System.out.println("延迟操作出现问题,但并不影响功能");
}
System.out.println("连接中。。。");
}
client.send("客户端发送请求");
} catch (URISyntaxException e) {
System.out.println(e.getMessage());
}
return null;
}
}
public class DemoApplication {
public static void main(String[] args){
WsClient javaClient = new WsClient();
javaClient.getClient("ws://127.0.0.1/websocket/service");
}
}