根据业务需求,许多场景下都需要用到即时推送的技术。首先当即研究了一下怎么引入该实用组件。
1.maven引入依赖
(此处用的是spring的websocket)这边会涉及到版本依赖的问题(如果版本不兼容会出现classNotDefind/方法找不到等问题),这里暂不考虑(我们项目spring引入的也是这个版本,同版本一般不会出问题)
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
2.创建一个spring-websocket.xml
(抽出来比较容易维护),并且这边涉及到了两种写法(一种被注释的,但是亲测都是可以使用的,就看你喜欢哪一种)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:websocket="http://www.springframework.org/schema/websocket"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/websocket
http://www.springframework.org/schema/websocket/spring-websocket.xsd
">
<!-- <bean id="myWebSocketConfig" class="com.gss.fruitmall.we.websocket.config.MyWebSocketConfig" /> -->
<bean id="websocket" class="com.gss.fruitmall.we.websocket.handler.MyWebSocketHandler" />
<websocket:handlers allowed-origins="*" >
<websocket:mapping path="/websocket" handler="websocket" />
<websocket:handshake-interceptors>
<bean class="com.gss.fruitmall.we.websocket.interceptor.MyHandshakeInterceptor" />
</websocket:handshake-interceptors>
</websocket:handlers>
</beans>
上面的xml中的 http://www.springframework.org/schema/websocket/spring-websocket.xsd 配置导致我调试了很久,因为如果使用spring-websocket-4.0.xsd,下面的那种配置没法配置allowed-origins 没有这个属性,博主纠结呀。(主要还是想两种方法都实践成功 =- = ,毕竟要理解一个东西,先能跑起来是比较有利的)
3.创建类
(两种方法使用到的类有所不同,在配置和类中都可以提现出来)
3.1方法一
MyWebSocketConfig第一种方法,作为socket配置监听,来分配处理类和拦截器
package com.gss.fruitmall.we.websocket.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
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 com.gss.fruitmall.we.websocket.handler.MyWebSocketHandler;
import com.gss.fruitmall.we.websocket.interceptor.MyHandshakeInterceptor;
@Configuration
@EnableWebMvc
@EnableWebSocket
public class MyWebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer{
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(getHandler(), "/websocket").setAllowedOrigins("*").addInterceptors(getInterceptor());
}
@Bean
public MyWebSocketHandler getHandler() {
return new MyWebSocketHandler();
}
@Bean
public MyHandshakeInterceptor getInterceptor() {
return new MyHandshakeInterceptor();
}
}
3.2 方法二
MyWebSocketHandler 主要的消息处理类,这边只做简单处理
package com.gss.fruitmall.we.websocket.handler;
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.WebSocketHandler;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
public class MyWebSocketHandler implements WebSocketHandler {
private static final Logger log = Logger.getLogger(MyWebSocketHandler.class);
private static final ArrayList<WebSocketSession> users = new ArrayList<WebSocketSession>();
// 初次链接成功执行
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
users.add(session);
}
// 接受消息处理消息
public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> webSocketMessage)
throws Exception {
// sendMessageToUsers(new TextMessage(webSocketMessage.getPayload() + ""));
// sendMessageToUser(userName, new TextMessage(webSocketMessage.getPayload() +
// ""));
}
public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throws Exception {
if (webSocketSession.isOpen()) {
webSocketSession.close();
}
users.remove(webSocketSession);
}
public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception {
// System.out.println(webSocketSession.getAttributes().get("WEBSOCKET_USERID"));
users.remove(webSocketSession);
}
public boolean supportsPartialMessages() {
return false;
}
/**
* 给所有在线用户发送消息
*
* @param message
*/
public static int sendMessageToUsers(TextMessage message) {
int senCount = 0;
for (WebSocketSession user : users) {
try {
if (user.isOpen()) {
user.sendMessage(message);
senCount++;
}
} catch (IOException e) {
e.printStackTrace();
log.error("推送所有用户错误", e);
}
}
return senCount;
}
/**
* 给某个用户发送消息,模拟给admin发信息
*
* @param userId
* @param message
*/
public static void sendMessageToUser(String userId, TextMessage message) {
for (WebSocketSession user : users) {
if (user.getAttributes().get("WEBSOCKET_USERID").equals(userId)) {
try {
if (user.isOpen()) {
user.sendMessage(message);
}
} catch (IOException e) {
e.printStackTrace();
log.error("推送用户错误", e);
}
break;
}
}
}
}
3.3 MyHandshakeInterceptor拦截器,可扩展
package com.gss.fruitmall.we.websocket.interceptor;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;
import me.chanjar.weixin.common.util.StringUtils;
/**
* 拦截器
*/
public class MyHandshakeInterceptor implements HandshakeInterceptor {
// 初次握手访问前
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse serverHttpResponse,
WebSocketHandler webSocketHandler, Map<String, Object> map) throws Exception {
if (request instanceof ServletServerHttpRequest) {
HttpServletRequest servletRequest = ((ServletServerHttpRequest) request).getServletRequest();
String userId = servletRequest.getParameter("userId");
// 使用userId区分WebSocketHandler,以便定向发送消息
if (StringUtils.isNotBlank(userId)) {
map.put("WEBSOCKET_USERID", userId);
servletRequest.getSession().setAttribute("WEBSOCKET_USERID", userId);
}
}
return true;
}
// 初次握手访问后
public void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse,
WebSocketHandler webSocketHandler, Exception e) {
}
}
如果是xml中注释的方法,拦截器和处理类类名都需要加上@Component注解以便注入配置里面。
这种配置都是使用以下方式连接
new WebSocket("ws://域名/项目名/websocket?userId=111")
另外,附加动态代理nginx配置websocket:
只要在拦截到的location中加入:或者不懂的可以都加 ( ̄▽ ̄)"
location ~ ^/test/wefruitmall/game/ { #这边是我拦截到需要处理的url
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}

本文介绍了在SSM框架下如何实现WebSocket服务端推送,包括maven依赖的引入,`spring-websocket.xml`配置文件的创建,两种不同的实现方法(MyWebSocketConfig和MyWebSocketHandler),以及MyHandshakeInterceptor拦截器的使用。此外,还提供了动态代理Nginx配置WebSocket的指导。
841

被折叠的 条评论
为什么被折叠?



