1.業(yè)務(wù)背景
? ? ? ? 負責的項目有一個搜索功能,搜索的范圍幾乎是全表掃,且數(shù)據(jù)源類型賊多。目前對搜索的數(shù)據(jù)量量級未知,但肯定不會太少,不僅需要搜索還得點擊下載文件。
?
? ? ? ? 關(guān)于搜索這塊類型 眾多,未了避免有個別極大數(shù)據(jù)源影響整個搜索效率,我采用多線程異步搜索,將搜索到每個數(shù)據(jù)源數(shù)據(jù)使用 websocket 響應(yīng)給前端。
2.遇到的問題
? ? ? ? 1 .想自定義接收前端消息的類型,因為接收的消息類型都是string 類型,所以一看肯定不符合我的需求。(唉,怪我沒多問)
? ? ? ? ? 思路: 其實接收是string一點不影響。直接上json,轉(zhuǎn)對象就行。
? ? ? ? 2. socket 什么時候關(guān)閉?
? ? ? ? ? 思路:
????????????????????1.心跳包檢測,心跳達到次數(shù)斷開socket。(前后端互發(fā)心跳)
? ? ? ? ? ? ? ? ? ? 2. 因為多線程,后端開啟線程監(jiān)聽線程有沒有執(zhí)行完的隊列還有沒有還沒執(zhí)行的任務(wù),沒有開始計時,達到時間關(guān)閉socket,若計時期間有任務(wù)重置計時。(后端監(jiān)聽)
3.相關(guān)資料
一文搞懂四種 WebSocket 使用方式_@enablewebsocket_Java架構(gòu)獅的博客-CSDN博客
4.代碼實現(xiàn)
? ? ? ? 1.注解寫法
/**
* 開啟WebSocket支持
* Created by huiyunfei on 2019/5/31.
*/
@Configuration
@EnableWebSocket
public class WebSocketConfig implements ServletContextInitializer {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
ServerEndpointExporter serverEndpointExporter = new ServerEndpointExporter();
return serverEndpointExporter;
}
/**
* 啟動加載
*
* @param servletContext
*/
@Override
public void onStartup(ServletContext servletContext) {
servletContext.addListener(WebAppRootListener.class);
// 接收base64的字符串,等于50M 解決上傳內(nèi)容過大問題
servletContext.setInitParameter("org.apache.tomcat.websocket.textBufferSize", "52428800");
servletContext.setInitParameter("org.apache.tomcat.websocket.binaryBufferSize", "52428800");
}
}
@OnOpen
public void onOpen(Session session) {
System.out.println("與前端建立了WebSocket連接");
this.session = session;
webSocketSet.add(this); //加入set中
// addOnlineCount(); //在線數(shù)加1
// log.info("有新窗口開始監(jiān)聽:"+sid+",當前在線人數(shù)為" + getOnlineCount());
this.sid=sid;
try {
sendMessage("連接成功");
} catch (IOException e) {
log.error("websocket IO異常");
}
}
@OnMessage
public void handleMessage(Session session, String message) throws IOException {
session.getBasicRemote().sendText("Reversed: " + new StringBuilder(message).reverse());
}
@OnClose
public void onClose(Session session) {
System.out.println("與前端斷開了WebSocket連接");
}
@OnError
public void onError(Throwable throwable) {
throwable.printStackTrace();
}
? ? ? ?注意:誰說是注解開發(fā),切記并不是發(fā)送http請求,下面是錯誤實例
? ? ? ? 上面我不是提到想自定義接收參數(shù),然后我一直以為加個注解就行。接收類型別動。
? ? ? ? ?不然就像苦逼的我程序都啟動不了,排錯半天時間。
@OnMessage
public void onMessage(Session session, FullSearchParam param) {
System.out.println("接收到前端發(fā)送的消息:" + param.getSearchContext());
try {
// fullSearch(param, session);
} catch (IOException e) {
e.printStackTrace();
} catch (EncodeException e) {
throw new RuntimeException(e);
}
}
? ? ? ? 2.實現(xiàn)接口
package com.trinity.web.controller.search.spring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
/**
* 開啟WebSocket支持
* Created by huiyunfei on 2019/5/31.
*/
@Configuration
@EnableWebSocket
public class SpringSocketConfig implements WebSocketConfigurer {
@Autowired
private SpringSocketHandle springSocketHandle;
@Autowired
private SpringAbstractWebSocketHandler springAbstractWebSocketHandler;
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(springSocketHandle, "/spring-ws").setAllowedOrigins("*")
.addHandler(springAbstractWebSocketHandler, "/spring-ws1").setAllowedOrigins("*");
}
}
? ? ? ? ? ? ? 這種方式接收消息需要判斷,因為 WebSocketMessage 是接口,spring 提供了三個實現(xiàn)類,分別是文本 字節(jié) ping,目前后兩種還不知道怎么使用。所以這種方式需要區(qū)判斷前端傳輸?shù)臄?shù)據(jù)類型分別處理。
@Component
public class SpringSocketHandle implements WebSocketHandler {
/**
* 連接成功后調(diào)用。
* @param session
* @throws Exception
*/
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
System.out.println("SpringSocketHandle, 收到新的連接: " + session.getId());
}
/**
* 處理發(fā)送來的消息
*
* @param session
* @param message
* @throws Exception
*/
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
String msg = "SpringSocketHandle, 連接:" + session.getId() + ",已收到消息。";
System.out.println(msg);
// this.handleMessage(session, );
session.sendMessage(new TextMessage(msg));
}
/**
* WS 連接出錯時調(diào)用
*
* @param session
* @param exception
* @throws Exception
*/
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
System.out.println("WS 連接發(fā)生錯誤");
}
/**
* 連接關(guān)閉后調(diào)用
*
* @param session
* @param closeStatus
* @throws Exception
*/
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
System.out.println("WS 關(guān)閉連接");
}
/**
* 支持分片消息
*
* @return
*/
@Override
public boolean supportsPartialMessages() {
return false;
}
? ? ? ? 這種方式就更加簡單不需要我們自己去判斷
@Slf4j
@Component
public class SpringAbstractWebSocketHandler extends AbstractWebSocketHandler {
/**
* 業(yè)務(wù)service
*/
@Autowired
private IDampDatasourceInfoService dampDatasourceInfoService;
@Autowired
private IDampAssetInfoService dampAssetInfoService;
@Autowired
private SearchThreadPool searchThreadPool;
@Autowired
private TokenService tokenService;
/**
* 靜態(tài)變量,用來記錄當前在線連接數(shù)。應(yīng)該把它設(shè)計成線程安全的。
*/
private static int onlineCount = 0;
/**
* concurrent包的線程安全Set,用來存放每個客戶端對應(yīng)的MyWebSocket對象。
*/
private static CopyOnWriteArraySet<SearchSocketServer> webSocketSet = new CopyOnWriteArraySet<SearchSocketServer>();
/**
* 與某個客戶端的連接會話,需要通過它來給客戶端發(fā)送數(shù)據(jù)
*/
private Session session;
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
log.info("接收到搜索的消息,搜索內(nèi)容為{}",message);
List<String> authorization = session.getHandshakeHeaders().get("Authorization");
FullSearchParam param = JSONObject.parseObject(message.getPayload(), FullSearchParam.class);
fullSearch(param, session);
}
protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception {
}
protected void handlePongMessage(WebSocketSession session, PongMessage message) throws Exception {
}
? ? ??5.總結(jié)
? ? ? ? 嘗試寫不會的代碼總是非常的認真,但也非常煎熬。
? ? ? ? 然后接收消息時用到了 SecurityUtils 公共方法 從token 獲取用戶id,但是卻出現(xiàn)獲取失敗。文章來源:http://www.zghlxwxcb.cn/news/detail-669951.html
? ? ? ? 明天再看文章來源地址http://www.zghlxwxcb.cn/news/detail-669951.html
public class SecurityUtils
{
/**
* 用戶ID
**/
public static Long getUserId()
{
try
{
return getLoginUser().getUserId();
}
catch (Exception e)
{
throw new ServiceException("獲取用戶ID異常", HttpStatus.UNAUTHORIZED);
}
}
/**
* 獲取用戶
**/
public static LoginUser getLoginUser()
{
try
{
return (LoginUser) getAuthentication().getPrincipal();
}
catch (Exception e)
{
throw new ServiceException("獲取用戶信息異常", HttpStatus.UNAUTHORIZED);
}
}
/**
* 獲取Authentication
*/
public static Authentication getAuthentication()
{
return SecurityContextHolder.getContext().getAuthentication();
}
到了這里,關(guān)于spring boot 項目整合 websocket的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!