Spring+Websocket實現訊息的推送
摘要: 本文主要有三個步驟 1、使用者登入後建立websocket連線,預設選擇websocket連線,如果瀏覽器不支援,則使用sockjs進行模擬連線 2、建立連線後,服務端返回該使用者的未讀訊息 3、服務端進行相關操作後,推送給某一個使用者或者所有使用者新訊息 相關環境 Spring4.0.6(要選擇4.0+),tomcat7.0.55
Websocet服務端實現
WebSocketConfig.java
@Configuration
@EnableWebMvc
@EnableWebSocket
public class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(systemWebSocketHandler(),"/webSocketServer").addInterceptors(new WebSocketHandshakeInterceptor());
registry.addHandler(systemWebSocketHandler(), "/sockjs/webSocketServer").addInterceptors(new WebSocketHandshakeInterceptor())
.withSockJS();
}
@Bean
public WebSocketHandler systemWebSocketHandler(){
return new SystemWebSocketHandler();
}
}
不要忘記在springmvc的配置檔案中配置對此類的自動掃描
<context:component-scan base-package="com.ldl.origami.websocket" />
@Configuration
@EnableWebMvc
@EnableWebSocket
這三個大致意思是使這個類支援以@Bean的方式載入bean,並且支援springmvc和websocket,不是很準確大致這樣,試了一下@EnableWebMvc不加也沒什麼影響,@Configuration本來就支援springmvc的自動掃描
registry.addHandler(systemWebSocketHandler(),"/webSocketServer").addInterceptors(new WebSocketHandshakeInterceptor())
用來註冊websocket server實現類,第二個引數是訪問websocket的地址
registry.addHandler(systemWebSocketHandler(), "/sockjs/webSocketServer").addInterceptors(new WebSocketHandshakeInterceptor())
.withSockJS();
}
這個是使用Sockjs的註冊方法
首先SystemWebSocketHandler.java
public class SystemWebSocketHandler implements WebSocketHandler {
private static final Logger logger;
private static final ArrayList<WebSocketSession> users;
static {
users = new ArrayList<>();
logger = LoggerFactory.getLogger(SystemWebSocketHandler.class);
}
@Autowired
private WebSocketService webSocketService;
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
logger.debug("connect to the websocket success......");
users.add(session);
String userName = (String) session.getAttributes().get(Constants.WEBSOCKET_USERNAME);
if(userName!= null){
//查詢未讀訊息
int count = webSocketService.getUnReadNews((String) session.getAttributes().get(Constants.WEBSOCKET_USERNAME));
session.sendMessage(new TextMessage(count + ""));
}
}
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
//sendMessageToUsers();
}
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
if(session.isOpen()){
session.close();
}
logger.debug("websocket connection closed......");
users.remove(session);
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
logger.debug("websocket connection closed......");
users.remove(session);
}
@Override
public boolean supportsPartialMessages() {
return false;
}
/**
* 給所有線上使用者傳送訊息
*
* @param message
*/
public void sendMessageToUsers(TextMessage message) {
for (WebSocketSession user : users) {
try {
if (user.isOpen()) {
user.sendMessage(message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 給某個使用者傳送訊息
*
* @param userName
* @param message
*/
public void sendMessageToUser(String userName, TextMessage message) {
for (WebSocketSession user : users) {
if (user.getAttributes().get(Constants.WEBSOCKET_USERNAME).equals(userName)) {
try {
if (user.isOpen()) {
user.sendMessage(message);
}
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
}
}
然後WebSocketHandshakeInterceptor.java
public class WebSocketHandshakeInterceptor implements HandshakeInterceptor {
private static Logger logger = LoggerFactory.getLogger(HandshakeInterceptor.class);
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object
> attributes) throws Exception {
if (request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
HttpSession session = servletRequest.getServletRequest().getSession(false);
if (session != null) {
//使用userName區分WebSocketHandler,以便定向傳送訊息
String userName = (String) session.getAttribute(Constants.SESSION_USERNAME);
attributes.put(Constants.WEBSOCKET_USERNAME,userName);
}
}
return true;
}
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
}
}
這個的主要作用是取得當前請求中的使用者名稱,並且儲存到當前的WebSocketHandler中,以便確定WebSocketHandler所對應的使用者,具體可參考HttpSessionHandshakeInterceptor
使用者登入建立websocket連線
index.jsp
<script type="text/javascript" src="http://localhost:8080/Origami/websocket/sockjs-0.3.min.js"></script>
<script>
var websocket;
if ('WebSocket' in window) {
websocket = new WebSocket("ws://localhost:8080/Origami/webSocketServer");
} else if ('MozWebSocket' in window) {
websocket = new MozWebSocket("ws://localhost:8080/Origami/webSocketServer");
} else {
websocket = new SockJS("http://localhost:8080/Origami/sockjs/webSocketServer");
}
websocket.onopen = function (evnt) {
};
websocket.onmessage = function (evnt) {
$("#msgcount").html("(<font color='red'>"+evnt.data+"</font>)")
};
websocket.onerror = function (evnt) {
};
websocket.onclose = function (evnt) {
}
</script>
使用sockjs時要注意
1、這兩個的寫法
<script type="text/javascript" src="http://localhost:8080/Origami/websocket/sockjs-0.3.min.js"></script>
websocket = new SockJS("http://localhost:8080/Origami/sockjs/webSocketServer");
2、web.xml中
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_1.xsd">
version
web-app_3_1.xsd
這兩個的版本都要是3.0+
然後在這個servlet中加入
<async-supported>true</async-supported>
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
然後所有的filter中也加入
<async-supported>true</async-supported>
3、新增相關依賴
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.3.3</version>
</dependency>
好了,現在websocket可以正常建立起來了
返回使用者未讀的訊息
當連線建立後,會進入SystemWebSocketHandler的afterConnectionEstablished方法,程式碼看上邊,取出WebSocketHandshakeInterceptor中儲存的使用者名稱
查詢資訊後使用session.sendMessage(new TextMessage(count + ""));返回給使用者,從哪來回哪去
服務端推送訊息給使用者
@Controller
public class AdminController {
static Logger logger = LoggerFactory.getLogger(AdminController.class);
@Autowired(required = false)
private AdminService adminService;
@Bean
public SystemWebSocketHandler systemWebSocketHandler() {
return new SystemWebSocketHandler();
}
@RequestMapping("/auditing")
@ResponseBody
public String auditing(HttpServletRequest request){
//無關程式碼都省略了
int unReadNewsCount = adminService.getUnReadNews(username);
systemWebSocketHandler().sendMessageToUser(username, new TextMessage(unReadNewsCount + ""));
return result;
}
}
在這裡可以使用sendMessageToUser給某個使用者推送資訊,也可以使用sendMessageToUsers給所有使用者推送資訊
相關文章
- workerman 實現訊息推送
- Flutter websocket 實現訊息推送FlutterWeb
- PHP與反ajax推送,實現的訊息實時推送功能PHP
- PHP基於Redis訊息佇列實現的訊息推送的方法PHPRedis佇列
- Knative 實戰:基於 Kafka 實現訊息推送Kafka
- 基於 Hyperf 實現 RabbitMQ + WebSocket 訊息推送MQWeb
- 實時訊息推送整理
- 7種 實現web實時訊息推送的方案,7種!Web
- 訊息的即時推送——net實現、websocket實現以及socket.io實現Web
- Laravel 實現 Kafka 訊息推送與接收處理LaravelKafka
- 實時訊息推送方案-SSE
- WebSocket 實現伺服器訊息推送客戶端Web伺服器客戶端
- 基於workerman實現的web訊息推送站內信功能Web
- 小程式訂閱訊息推送(含原始碼)java實現小程式推送,springboo原始碼JavaSpring
- python 實現公眾號模板訊息推送(親測有效)Python
- WebSocket實現服務端推送訊息和聊天會話Web服務端會話
- App如何利用推送訊息有效實現拉新促活?APP
- 造輪子之訊息實時推送
- 訊息推送背後的思考
- iOS使用觀察者模式實現推送訊息模組化iOS模式
- 在spring boot中訊息推送系統設計與實現Spring Boot
- 一個簡單API,一鍵實現多通道訊息推送API
- 微信雲託管 WebSocket 實戰:基於模版實現訊息推送Web
- RocksDB 在 vivo 訊息推送系統中的實踐
- workerman做實時訊息推送,用過沒?
- 用 Laravel 自帶訊息模組搭建小程式實時推送訊息Laravel
- 想要更精準的小程式模版訊息推送?我們來幫你實現
- java實現 微信公眾號推送訊息 ,cv 就可執行!!!Java
- 3個步驟輕鬆整合Push Kit,實現App訊息推送APP
- 一起來實現單使用者登入 —— 訊息推送
- 訊息推送平臺的實時數倉?!flink消費kafka訊息入到hiveKafkaHive
- Android之訊息推送原理Android
- 搞掂釘釘訊息推送!
- Android 訊息推送:第三方訊息推送平臺 詳細解析Android
- Spring Boot 整合 WebSocket 實現服務端推送訊息到客戶端Spring BootWeb服務端客戶端
- 使用pushplus+python實現亞馬遜到貨訊息推送微信Python亞馬遜
- Service Worker學習與實踐(三)——訊息推送
- 未讀訊息(小紅點),前端與 RabbitMQ實時訊息推送實踐,賊簡單~前端MQ
- 番外訊息推送篇_05