我現在有兩種方法
第一種:使用java封裝的這個包下的javax.websocket.*
先配置這個配置類
import com.alibaba.nacos.common.utils.CollectionUtils;
import org.springframework.stereotype.Component;import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;
import java.util.List;
import java.util.Map;@Component
public class WebSocketServerConfig extends ServerEndpointConfig.Configurator {@Overridepublic boolean checkOrigin(String originHeaderValue) {//todo webSocket的 過濾 權限校驗return true;}@Overridepublic void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {Map<String, List<String>> parameterMap = request.getParameterMap();List<String> erpList = parameterMap.get("erp");if(!CollectionUtils.isEmpty(erpList)){sec.getUserProperties().put("erp", erpList.get(0));}}}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}}
?創建一個socket
前端應該怎么連接呢
?
第二種:使用spring自定義的websocket + Disruptor。
?先定義這個配置
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {@Resourceprivate PictureEditHandler pictureEditHandler;@Resourceprivate WsHandshakeInterceptor wsHandshakeInterceptor;@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {// websocketregistry.addHandler(pictureEditHandler, "/ws/picture/edit").addInterceptors(wsHandshakeInterceptor).setAllowedOrigins("*");}
}
再配置攔截器
/*** WebSocket 攔截器,建立連接前校驗*/
@Slf4j
@Component
public class WsHandshakeInterceptor implements HandshakeInterceptor {@Resourceprivate UserService userService;@Resourceprivate PictureService pictureService;@Resourceprivate SpaceService spaceService;@Resourceprivate SpaceUserAuthManager spaceUserAuthManager;/*** 建立連接前要校驗* @param request* @param response* @param wsHandler* @param attributes 給Session會話設置屬性* @return* @throws Exception*/@Overridepublic boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {if (request instanceof ServletServerHttpRequest) {HttpServletRequest httpServletRequest = ((ServletServerHttpRequest) request).getServletRequest();// 從請求中獲取用戶信息String pictureId = httpServletRequest.getParameter("pictureId");if (StrUtil.isBlank(pictureId)){log.info("缺少圖片參數,拒絕握手");return false;}// 獲取當前登入用戶User loginUser = userService.getLoginUser(httpServletRequest);if (ObjUtil.isEmpty(loginUser)){log.info("用戶未登錄,拒絕握手");return false;}// 校驗用戶是否有編輯當前圖片的權限Picture picture = pictureService.getById(pictureId);if (ObjUtil.isEmpty(picture)){log.info("圖片不存在,拒絕握手");return false;}Long spaceId = picture.getSpaceId();Space space =null;if (spaceId != null){space= spaceService.getById(spaceId);if (ObjUtil.isEmpty(space)){log.info("圖片所在空間不存在,拒絕握手");return false;}if (space.getSpaceType() != SpaceTypeEnum.TEAM.getValue()){log.info("圖片所在空間不是團隊空間,拒絕握手");return false;}}List<String> permissionList = spaceUserAuthManager.getPermissionList(space, loginUser);if (!permissionList.contains(SpaceUserPermissionConstant.PICTURE_EDIT)){log.info("用戶沒有編輯圖片的權限,拒絕握手");return false;}// 設置用戶登入信息等屬性到 WebSocket 會話中attributes.put("user", loginUser);attributes.put("userId", loginUser.getId());attributes.put("pictureId", Long.valueOf(pictureId)); // 記得轉換為 Long 類型}return true;}@Overridepublic void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {}
}
?再寫這個disrupter的配置 這個東西就像一個工廠一樣,但是不是啊。它可以根據消費者的消息類型來調用對應的方法。
/**
*disruptor 配置*/
@Configuration
public class PictureEditEventDisruptorConfig {@Resourceprivate PictureEditEventWorkHandler pictureEditEventWorkHandler;@Bean("pictureEditEventDisruptor")public Disruptor<PictureEditEvent> messageModelRingBuffer() {// ringBuffer 的大小int bufferSize = 1024 * 256;Disruptor<PictureEditEvent> disruptor = new Disruptor<>(PictureEditEvent::new,bufferSize,ThreadFactoryBuilder.create().setNamePrefix("pictureEditEventDisruptor").build());// 設置消費者disruptor.handleEventsWithWorkerPool(pictureEditEventWorkHandler);// 開啟 disruptordisruptor.start();return disruptor;}
}
消費者 舉的一個例子?
/*** (消費者) 這只是一個例子*/
@Slf4j
@Component
public class PictureEditEventWorkHandler implements WorkHandler<PictureEditEvent> {@Resource@Lazyprivate PictureEditHandler pictureEditHandler;@Resourceprivate UserService userService;@Overridepublic void onEvent(PictureEditEvent event) throws Exception {PictureEditRequestMessage pictureEditRequestMessage = event.getPictureEditRequestMessage();WebSocketSession session = event.getSession();User user = event.getUser();Long pictureId = event.getPictureId();// 獲取到消息類別String type = pictureEditRequestMessage.getType();PictureEditMessageTypeEnum pictureEditMessageTypeEnum = PictureEditMessageTypeEnum.valueOf(type);// 調用對應的消息處理方法switch (pictureEditMessageTypeEnum) {case ENTER_EDIT:pictureEditHandler.handleEnterEditMessage(pictureEditRequestMessage, session, user, pictureId);break;case EDIT_ACTION:pictureEditHandler.handleEditActionMessage(pictureEditRequestMessage, session, user, pictureId);break;case EXIT_EDIT:pictureEditHandler.handleExitEditMessage(pictureEditRequestMessage, session, user, pictureId);break;default:PictureEditResponseMessage pictureEditResponseMessage = new PictureEditResponseMessage();pictureEditResponseMessage.setType(PictureEditMessageTypeEnum.ERROR.getValue());pictureEditResponseMessage.setMessage("消息類型錯誤");pictureEditResponseMessage.setUser(userService.getUserVO(user));session.sendMessage(new TextMessage(JSONUtil.toJsonStr(pictureEditResponseMessage)));}}
}
生產者的例子使用方法
/***生產者*/
@Component
@Slf4j
public class PictureEditEventProducer {@ResourceDisruptor<PictureEditEvent> pictureEditEventDisruptor;public void publishEvent(PictureEditRequestMessage pictureEditRequestMessage, WebSocketSession session, User user, Long pictureId) {RingBuffer<PictureEditEvent> ringBuffer = pictureEditEventDisruptor.getRingBuffer();// 獲取可以生成的位置long next = ringBuffer.next();PictureEditEvent pictureEditEvent = ringBuffer.get(next);pictureEditEvent.setSession(session);pictureEditEvent.setPictureEditRequestMessage(pictureEditRequestMessage);pictureEditEvent.setUser(user);pictureEditEvent.setPictureId(pictureId);// 發布事件ringBuffer.publish(next);}/*** 優雅停機*/@PreDestroypublic void close() {pictureEditEventDisruptor.shutdown(); // 默認處理完全部事件,再關閉}
}
最后就是處理websocket的方法里面是發送消息的所有方法和實現,
/*** WebSocket處理器*/
@Component
public class PictureEditHandler extends TextWebSocketHandler {@Resourceprivate PictureEditEventProducer pictureEditEventProducer;
}