1.引入依赖
java
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2.配置websocket服务
java
@Configuration
public class WebSocketConfig {
/**
* 配置WebSocket服务
* @return
*/
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
3.启动类添加注解
java
@EnableWebSocket
4.websocket服务端逻辑
java
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* WebSocketServer服务端
*/
@Slf4j
@Component
@ServerEndpoint("/websocket/{uid}")
public class WebSocketClient {
/**
* 静态变量,用来记录当前在线连接数,线程安全的类。
*/
private static AtomicInteger onlineSessionClientCount = new AtomicInteger(0);
/**
* 存放所有在线的客户端
*/
private static Map<String, Session> onlineSessionClientMap = new ConcurrentHashMap<>();
/**
* 连接uid和连接会话
*/
private String uid;
private Session session;
/**
* 连接建立成功调用的方法。由前端<code>new WebSocket</code>触发
*
* @param uid 每次页面建立连接时传入到服务端的id,比如用户id等。可以自定义。
* @param session 与某个客户端的连接会话,需要通过它来给客户端发送消息
*/
@OnOpen
public void onOpen(@PathParam("uid") String uid, Session session) {
/**
* session.getId():当前session会话会自动生成一个id,从0开始累加的。
*/
log.info("连接建立中 ==> session_id = {}, sid = {}", session.getId(), uid);
//加入 Map中。将页面的uid和session绑定或者session.getId()与session
//onlineSessionIdClientMap.put(session.getId(), session);
onlineSessionClientMap.put(uid, session);
//在线数加1
onlineSessionClientCount.incrementAndGet();
this.uid = uid;
this.session = session;
sendToOne(uid, "连接成功");
log.info("连接建立成功,当前在线数为:{} ==> 开始监听新连接:session_id = {}, sid = {},。", onlineSessionClientCount, session.getId(), uid);
}
/**
* 连接关闭调用的方法。由前端<code>socket.close()</code>触发
*
* @param uid
* @param session
*/
@OnClose
public void onClose(@PathParam("uid") String uid, Session session) {
//onlineSessionIdClientMap.remove(session.getId());
// 从 Map中移除
onlineSessionClientMap.remove(uid);
//在线数减1
onlineSessionClientCount.decrementAndGet();
log.info("连接关闭成功,当前在线数为:{} ==> 关闭该连接信息:session_id = {}, sid = {},。", onlineSessionClientCount, session.getId(), uid);
}
/**
* 收到客户端消息后调用的方法。由前端<code>socket.send</code>触发
* * 当服务端执行toSession.getAsyncRemote().sendText(xxx)后,前端的socket.onmessage得到监听。
*
* @param message
* @param session
*/
@OnMessage
public void onMessage(String message, Session session) {
/**
* html界面传递来得数据格式,可以自定义.
* {"sid":"user-1","message":"hello websocket"}
*/
log.info("接收到消息-----------------"+message);
List<String> uids = session.getRequestParameterMap().get("uid");
for (String uid : uids) {
// 接收前端拖推送改的消息
sendToOne(uid, "来自服务端的推送=====》你好前端! 我已经成功收到消息!消息数据为:" + message);
}
}
/**
* 发生错误调用的方法
*
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
log.error("WebSocket发生错误,错误信息为:" + error.getMessage());
error.printStackTrace();
}
/**
* 群发消息
*
* @param message 消息
*/
public void sendToAll(String message) {
// 遍历在线map集合
onlineSessionClientMap.forEach((onlineSid, toSession) -> {
// 排除掉自己
if (!uid.equalsIgnoreCase(onlineSid)) {
log.info("服务端给客户端群发消息 ==> sid = {}, toSid = {}, message = {}", uid, onlineSid, message);
toSession.getAsyncRemote().sendText(message);
}
});
}
/**
* 指定发送消息
*
* @param toUid
* @param message
*/
public boolean sendToOne(String toUid, String message) {
/*
* 判断发送者是否在线
*/
Session toSession = onlineSessionClientMap.get(toUid);
if (toSession == null) {
log.error("服务端给客户端发送消息 ==> toSid = {} 不存在, message = {}", toUid, message);
return false;
}
// 异步发送
log.info("服务端给客户端发送消息 ==> toSid = {}, message = {}", toUid, message);
toSession.getAsyncRemote().sendText(message);
return true;
}
}
5.service层调用推送消息方法
java
@Service
public class WebSocketHandler {
@Resource
private WebSocketClient webSocketClient;
public boolean sendMessageOne(String userId,String content) {
boolean flag = webSocketClient.sendToOne(userId,content);
return flag;
}
}
6.controller层逻辑
java
@PostMapping("/send")
public Map push2(@RequestBody PushDTO pushDTO){
Map map = new HashMap();
//1、参数校验,非空~
if(StringUtils.isEmpty(pushDTO.getMessage()) || pushDTO.getUserId() == null || pushDTO.getPushType() == null ) {
log.info("【消息推送】 参数异常");
map.put("code","-1");
map.put("msg","参数异常");
return map;
}
//2、推送消息
boolean flag = webSocketHandler.sendMessageOne(pushMessage.getUserId() + "", content);
//3、如果推送成功,修改状态,返回正确的JSON
if(flag){
PushMessage updatePushMessage = new PushMessage();
updatePushMessage.setId(pushMessage.getId());
updatePushMessage.setPushState(PUSH_SUCCESS);
// pushMessageService.updateById(updatePushMessage);
map.put("code","200");
map.put("msg","成功");
return map;
}
//4、返回用户未上线的JSON
map.put("code","500");
map.put("msg","用户离线");
return map;
}