近期公司消息中心组件中想增加一个功能:后端能够向web前端发送消息,也就是我们所说的站内信,于是我们想到了WebSocket通信这一技术实现,实现步骤如下:
1.定义WebSocket配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* @Author:
* @Description: WebSocket配置
* @Date: 2020/2/17
**/
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
2.定义websocket服务器
import com.cjkj.message.push.util.StringUtils;
import com.cjkj.message.utils.WebSocketUtil;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
/**
* @Description: 向前端实时推送消息
* @Date: 2020/2/17
**/
@Component
@ServerEndpoint(value = "/websocket/{userKey}")
@Slf4j
public class WebSocketController {
/**
* @Description: 加入连接
* @Param userKey: 用户标识
* @Param session:
* @Return:
**/
@OnOpen
public void onOpen(@PathParam("userKey") String userKey, Session session) {
log.info("[" + userKey + "]加入连接!");
WebSocketUtil.addSession(userKey, session);
}
/**
* @Description: 断开连接
* @Param userKey: 用户标识
* @Param session:
* @Return:
**/
@OnClose
public void onClose(@PathParam("userKey") String userKey, Session session) {
log.info("[" + userKey + "]断开连接!");
WebSocketUtil.remoteSession(userKey);
}
/**
* @Description: 发送消息
* @Param userKey: 用户标识
* @Param message: 消息
* @Return:
**/
@OnMessage
public boolean OnMessage(@PathParam("userKey") String userKey, String message) {
if(StringUtils.isEmpty(userKey) || StringUtils.isEmpty(message)){
log.info("[参数userKey:{}, message:{}]", userKey, message);
return false;
}
log.info("服务器对[{}]发送消息:{}", userKey, message);
Session session = WebSocketUtil.ONLINE_SESSION.get(userKey);
//发送普通信息
return WebSocketUtil.sendMessage(session, message);
}
@OnError
public void onError(Session session, Throwable throwable) {
log.error(session.getId() + "异常:", throwable);
try {
session.close();
} catch (IOException e) {
e.printStackTrace();
}
throwable.printStackTrace();
}
}
3.定义推送功能
import com.cjkj.common.model.ResultData;
import com.cjkj.message.dto.req.WebSocketMsg;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Description: 向前端推送消息
* @Date: 2020/2/17
**/
@RestController
@RequestMapping("/socket")
public class WebSocketPushController {
@Autowired
private WebSocketController webSocketController;
/**
* @Description:
* @Param appNo: 用户标识
* @Param message: 发送的信息
* @Return:
**/
@PostMapping("/push")
public ResultData pushToWeb(@RequestBody WebSocketMsg webSocketMsg) {
webSocketController.OnMessage(webSocketMsg.getUserKey(), webSocketMsg.getMessage());
return ResultData.ok();
}
}
4.websocket消息发送工具类
import lombok.extern.slf4j.Slf4j;
import javax.websocket.RemoteEndpoint.Async;
import javax.websocket.Session;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
/**
* @Description:
* @Date: 2019/7/16
**/
@Slf4j
public class WebSocketUtil {
/**
* @Description: 使用map进行存储在线的session
**/
public static final Map<String, Session> ONLINE_SESSION = new ConcurrentHashMap<>();
/**
* @Description: 添加Session
* @Param userKey:
* @Param session:
* @Return:
**/
public static void addSession(String userKey, Session session) {
ONLINE_SESSION.put(userKey, session);
}
public static void remoteSession(String userKey) {
ONLINE_SESSION.remove(userKey);
}
/**
* @Description: 向某个用户发送消息
* @Param session:
* @Param message:
* @Return:
**/
public static Boolean sendMessage(Session session, String message) {
if (session == null) {
return false;
}
// getAsyncRemote()和getBasicRemote()异步与同步
Async async = session.getAsyncRemote();
//发送消息
Future<Void> future = async.sendText(message);
boolean done = future.isDone();
log.info("服务器发送消息给客户端[{}]的消息:{},状态为:{}", session.getId(), message, done);
return done;
}
}
5.测试
使用第三方工具连接:http://www.websocket-test.com/ 模拟前端