springmvc集成websocket

    最近项目中需要完成信息的实时显示功能,因此考虑使用websocket来实现,废话不多说,直接上配置流程及代码。

1.  首先引入需要的jar包,spring和springmvc的自然不多说,主要是引入spring集成的websocket包

               <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${spring.version}</version>

</dependency>


2. 编写websocket配置类,当然也可以在xml配置(这里就不多说了)

    编写自己的WebSocketConfig  extends WebMvcConfigurerAdapter implements WebSocketConfigurer

   编写这个类主要是为了实现WebSocketConfigurer.registerWebSocketHandlers方法给websocket注册消息处理器WebSocketHandler。具体实现如下:

@Configuration
@EnableWebMvc
@EnableWebSocket
public class WebSocketConfig extends WebMvcConfigurerAdapter implements
WebSocketConfigurer {

@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
// 前台 可以使用websocket环境
registry.addHandler(webSocketHandler(), "/websocket").addInterceptors(new HandshakeInterceptor());
// 前台 不可以使用websocket环境,则使用sockjs进行模拟连接

registry.addHandler(webSocketHandler(),"/sockjs/websocket").addInterceptors(

                        new  HandshakeInterceptor()).withSockJS();

}

// websocket 处理类
@Bean
public WebSocketHandler webSocketHandler() {
return new MySocketHandler();
}

}


3.  编写websocket消息处理器MySocketHandler implements WebSocketHandler

这个类是为了处理前端发送的消息或推送消息给前端,也对所有的连接进行管理

public class MyWebSocketHandler implements WebSocketHandler {
private static final Logger log = Logger.getLogger(ICWantWebSocketHandler.class);
@Autowired
RedisUtils redisUtils;
// 保存所有的用户session
private static final Map<String, WebSocketSession> users = new HashMap<>();

// 连接 就绪时
@Override
public void afterConnectionEstablished(WebSocketSession session)
throws Exception {
log.info("connect websocket success.......");
        //这块会实现自己业务,比如,当用户登录后,会把离线消息推送给用户
        //TextMessage returnMessage = new TextMessage("你将收到的离线");
        //session.sendMessage(returnMessage);
String username= (String) session.getAttributes().get("WEBSOCKET_USERNAME");
System.out.println(username);
System.out.println(session.getId());

//判断是否有同名连接,若存在则关闭
WebSocketSession s = users.get(username);
if(null != s && s.isOpen())
s.close();
users.put(username, session);
System.out.println("connect to the websocket success......当前数量:"+users.size());
}

// 处理前端发送的消息信息
@Override
public void handleMessage(WebSocketSession session,
WebSocketMessage<?> message) throws Exception {
//获取消息体
String msg = message.getPayload().toString();
if(msg.startsWith("java.nio.HeapByteBuffer")){
System.out.println("浏览器发送的心跳包");
return;
}

}

// 处理传输时异常
@Override
public void handleTransportError(WebSocketSession session,
Throwable exception) throws Exception {

//log.info("数据传输异常:  " + exception.getMessage());
}

// 关闭 连接时
@Override
public void afterConnectionClosed(WebSocketSession session,
CloseStatus closeStatus) throws Exception {

log.info("connect websocket closed.......");
String username= (String) session.getAttributes().get("WEBSOCKET_USERNAME");
        System.out.println("用户"+username+"已退出!");
        users.remove(username);
        System.out.println("剩余在线用户" + users.size());
}

@Override
public boolean supportsPartialMessages() {
return false;
}

// 给所有用户发送 信息
public void sendMsgToAllUsers(SocketMessageVO message) {
for (WebSocketSession user : users.values()) {
String msg = GsonUtil.object2JsonStr(message);
TextMessage textMsg = new TextMessage(msg);
try {
user.sendMessage(textMsg);
} catch (IOException e) {
log.error("XLTX-ERROR: websocket发送消息出错", e);
}
}
}

/**
* 发送消息给指定的用户
* @param SocketMessageVO  from_user 或 to_user为null时直接返回
*/
public void sendMsgToUser(SocketMessageVO message) {
if(message == null || message.getFrom_user() == null || message.getTo_user() == null)
return;
String toUser = message.getTo_user();

WebSocketSession session = users.get(toUser);
if(session == null)
return;
String msg = GsonUtil.object2JsonStr(message);
TextMessage textMsg = new TextMessage(msg);
try {
session.sendMessage(textMsg);
} catch (IOException e) {
log.error("XLTX-ERROR: websocket发送消息出错", e);
}
}

}


4. 编写握手拦截器 HandshakeInterceptor, 主要是为了在连接前将当前用户的信息保存起来,方便服务器推送信息

public class HandshakeInterceptor extends HttpSessionHandshakeInterceptor {
// 初次握手访问前
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
WebSocketHandler webSocketHandler, Map<String, Object> attributes)
throws Exception {

if (request instanceof ServletServerHttpRequest) {

Session httpSession = SecurityUtils.getSubject().getSession();

if(httpSession != null){
//使用userName区分WebSocketHandler,以便定向发送消息, 如果需要向指定的用户发送消息则需要记录用户信息
//因此这里将用户id绑定到websocket的session
UserVO userVO = (UserVO)httpSession.getAttribute(SysConstant.SESSION_USER_INFO);
if(userVO != null){
long uid = userVO.getId();
                String userName = String.valueOf(uid);
                if (userName==null) {
                    userName="default-system";
                }
    attributes.put("WEBSOCKET_USERNAME", userName);
}else
attributes.put("WEBSOCKET_USERNAME", httpSession.getId());
}
}
return super.beforeHandshake(request, response, webSocketHandler, attributes);
}


// 初次握手访问后
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response,
WebSocketHandler wsHandler, Exception e) {


super.afterHandshake(request, response, wsHandler, e);
}

}


以上个步骤就完成了websocket的服务端配置,在需要推送信息的类中注入消息处理器,即可进行消息推送。

前端的编写可以参考:https://blog.csdn.net/jared_he2017/article/details/79886600

猜你喜欢

转载自blog.csdn.net/jared_he2017/article/details/79886131