問題:依賴注入失敗,service獲取不到,提示null
這是參考代碼
package com.shier.ws;import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.google.gson.Gson;
import com.shier.config.HttpSessionConfig;
import com.shier.model.domain.Chat;
import com.shier.model.domain.Team;
import com.shier.model.domain.User;
import com.shier.model.request.MessageRequest;
import com.shier.model.vo.ChatMessageVO;
import com.shier.model.vo.WebSocketVO;
import com.shier.service.ChatService;
import com.shier.service.TeamService;
import com.shier.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.io.Serializable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;import static com.shier.constants.ChatConstant.*;
import static com.shier.constants.UserConstants.ADMIN_ROLE;
import static com.shier.constants.UserConstants.USER_LOGIN_STATE;/*** WebSocket服務*/
@Component
@Slf4j
@ServerEndpoint(value = "/websocket/{userId}/{teamId}", configurator = HttpSessionConfig.class)
public class WebSocket {/*** 保存隊伍的連接信息*/private static final Map<String, ConcurrentHashMap<String, WebSocket>> ROOMS = new HashMap<>();/*** 線程安全的無序的集合*/private static final CopyOnWriteArraySet<Session> SESSIONS = new CopyOnWriteArraySet<>();/*** 會話池*/private static final Map<String, Session> SESSION_POOL = new HashMap<>(0);/*** 用戶服務*/private static UserService userService;/*** 聊天服務*/private static ChatService chatService;/*** 團隊服務*/private static TeamService teamService;/*** 房間在線人數*/private static int onlineCount = 0;/*** 當前信息*/private Session session;/*** http會話*/private HttpSession httpSession;/*** 上網數** @return int*/public static synchronized int getOnlineCount() {return onlineCount;}/*** 添加在線計數*/public static synchronized void addOnlineCount() {WebSocket.onlineCount++;}/*** 子在線計數*/public static synchronized void subOnlineCount() {WebSocket.onlineCount--;}/*** 集熱地圖服務** @param userService 用戶服務*/@Resourcepublic void setHeatMapService(UserService userService) {WebSocket.userService = userService;}/*** 集熱地圖服務** @param chatService 聊天服務*/@Resourcepublic void setHeatMapService(ChatService chatService) {WebSocket.chatService = chatService;}/*** 集熱地圖服務** @param teamService 團隊服務*/@Resourcepublic void setHeatMapService(TeamService teamService) {WebSocket.teamService = teamService;}/*** 隊伍內群發消息** @param teamId 團隊id* @param msg 消息*/public static void broadcast(String teamId, String msg) {ConcurrentHashMap<String, WebSocket> map = ROOMS.get(teamId);// keySet獲取map集合key的集合 然后在遍歷key即可for (String key : map.keySet()) {try {WebSocket webSocket = map.get(key);webSocket.sendMessage(msg);} catch (Exception e) {e.printStackTrace();}}}/*** 發送消息** @param message 消息* @throws IOException ioexception*/public void sendMessage(String message) throws IOException {this.session.getBasicRemote().sendText(message);}/*** 開放** @param session 會話* @param userId 用戶id* @param teamId 團隊id* @param config 配置*/@OnOpenpublic void onOpen(Session session, @PathParam(value = "userId") String userId, @PathParam(value = "teamId") String teamId, EndpointConfig config) {try {if (StringUtils.isBlank(userId) || "undefined".equals(userId)) {sendError(userId, "參數有誤");return;}HttpSession httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());User user = (User) httpSession.getAttribute(USER_LOGIN_STATE);if (user != null) {this.session = session;this.httpSession = httpSession;}if (!"NaN".equals(teamId)) {if (!ROOMS.containsKey(teamId)) {ConcurrentHashMap<String, WebSocket> room = new ConcurrentHashMap<>(0);room.put(userId, this);ROOMS.put(String.valueOf(teamId), room);// 在線數加1addOnlineCount();} else {if (!ROOMS.get(teamId).containsKey(userId)) {ROOMS.get(teamId).put(userId, this);// 在線數加1addOnlineCount();}}} else {SESSIONS.add(session);SESSION_POOL.put(userId, session);sendAllUsers();}} catch (Exception e) {e.printStackTrace();}}/*** 關閉** @param userId 用戶id* @param teamId 團隊id* @param session 會話*/@OnClosepublic void onClose(@PathParam("userId") String userId, @PathParam(value = "teamId") String teamId, Session session) {try {if (!"NaN".equals(teamId)) {ROOMS.get(teamId).remove(userId);if (getOnlineCount() > 0) {subOnlineCount();}} else {if (!SESSION_POOL.isEmpty()) {SESSION_POOL.remove(userId);SESSIONS.remove(session);}sendAllUsers();}} catch (Exception e) {e.printStackTrace();}}/*** 消息** @param message 消息* @param userId 用戶id*/@OnMessagepublic void onMessage(String message, @PathParam("userId") String userId) {if ("PING".equals(message)) {sendOneMessage(userId, "pong");return;}MessageRequest messageRequest = new Gson().fromJson(message, MessageRequest.class);Long toId = messageRequest.getToId();Long teamId = messageRequest.getTeamId();String text = messageRequest.getText();Integer chatType = messageRequest.getChatType();User fromUser = userService.getById(userId);Team team = teamService.getById(teamId);if (chatType == PRIVATE_CHAT) {// 私聊privateChat(fromUser, toId, text, chatType);} else if (chatType == TEAM_CHAT) {// 隊伍內聊天teamChat(fromUser, text, team, chatType);} else {// 群聊hallChat(fromUser, text, chatType);}}/*** 隊伍聊天** @param user 用戶* @param text 文本* @param team 團隊* @param chatType 聊天類型*/private void teamChat(User user, String text, Team team, Integer chatType) {ChatMessageVO ChatMessageVO = new ChatMessageVO();WebSocketVO fromWebSocketVO = new WebSocketVO();BeanUtils.copyProperties(user, fromWebSocketVO);ChatMessageVO.setFormUser(fromWebSocketVO);ChatMessageVO.setText(text);ChatMessageVO.setTeamId(team.getId());ChatMessageVO.setChatType(chatType);ChatMessageVO.setCreateTime(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));if (user.getId() == team.getUserId() || user.getRole() == ADMIN_ROLE) {ChatMessageVO.setIsAdmin(true);}User loginUser = (User) this.httpSession.getAttribute(USER_LOGIN_STATE);if (loginUser.getId() == user.getId()) {ChatMessageVO.setIsMy(true);}String toJson = new Gson().toJson(ChatMessageVO);try {broadcast(String.valueOf(team.getId()), toJson);saveChat(user.getId(), null, text, team.getId(), chatType);chatService.deleteKey(CACHE_CHAT_TEAM, String.valueOf(team.getId()));} catch (Exception e) {throw new RuntimeException(e);}}/*** 大廳聊天** @param user 用戶* @param text 文本* @param chatType 聊天類型*/private void hallChat(User user, String text, Integer chatType) {ChatMessageVO ChatMessageVO = new ChatMessageVO();WebSocketVO fromWebSocketVO = new WebSocketVO();BeanUtils.copyProperties(user, fromWebSocketVO);ChatMessageVO.setFormUser(fromWebSocketVO);ChatMessageVO.setText(text);ChatMessageVO.setChatType(chatType);ChatMessageVO.setCreateTime(DateUtil.format(new Date(), "yyyy年MM月dd日 HH:mm:ss"));if (user.getRole() == ADMIN_ROLE) {ChatMessageVO.setIsAdmin(true);}User loginUser = (User) this.httpSession.getAttribute(USER_LOGIN_STATE);if (loginUser.getId() == user.getId()) {ChatMessageVO.setIsMy(true);}String toJson = new Gson().toJson(ChatMessageVO);sendAllMessage(toJson);saveChat(user.getId(), null, text, null, chatType);chatService.deleteKey(CACHE_CHAT_HALL, String.valueOf(user.getId()));}/*** 私聊** @param user 用戶* @param toId 為id* @param text 文本* @param chatType 聊天類型*/private void privateChat(User user, Long toId, String text, Integer chatType) {ChatMessageVO ChatMessageVO = chatService.chatResult(user.getId(), toId, text, chatType, DateUtil.date(System.currentTimeMillis()));User loginUser = (User) this.httpSession.getAttribute(USER_LOGIN_STATE);if (loginUser.getId() == user.getId()) {ChatMessageVO.setIsMy(true);}String toJson = new Gson().toJson(ChatMessageVO);sendOneMessage(toId.toString(), toJson);saveChat(user.getId(), toId, text, null, chatType);chatService.deleteKey(CACHE_CHAT_PRIVATE, user.getId() + "" + toId);chatService.deleteKey(CACHE_CHAT_PRIVATE, toId + "" + user.getId());}/*** 保存聊天** @param userId 用戶id* @param toId 為id* @param text 文本* @param teamId 團隊id* @param chatType 聊天類型*/private void saveChat(Long userId, Long toId, String text, Long teamId, Integer chatType) {
// if (chatType == PRIVATE_CHAT) {
// User user = userService.getById(userId);
// Set<Long> userIds = stringJsonListToLongSet(user.getFriendIds());
// if (!userIds.contains(toId)) {
// sendError(String.valueOf(userId), "該用戶不是你的好友");
// return;
// }
// }Chat chat = new Chat();chat.setFromId(userId);chat.setText(String.valueOf(text));chat.setChatType(chatType);chat.setCreateTime(new Date());if (toId != null && toId > 0) {chat.setToId(toId);}if (teamId != null && teamId > 0) {chat.setTeamId(teamId);}chatService.save(chat);}/*** 發送失敗** @param userId 用戶id* @param errorMessage 錯誤消息*/private void sendError(String userId, String errorMessage) {JSONObject obj = new JSONObject();obj.set("error", errorMessage);sendOneMessage(userId, obj.toString());}/*** 廣播消息** @param message 消息*/public void sendAllMessage(String message) {for (Session session : SESSIONS) {try {if (session.isOpen()) {synchronized (session) {session.getBasicRemote().sendText(message);}}} catch (Exception e) {e.printStackTrace();}}}/*** 發送一個消息** @param userId 用戶編號* @param message 消息*/public void sendOneMessage(String userId, String message) {Session session = SESSION_POOL.get(userId);if (session != null && session.isOpen()) {try {synchronized (session) {session.getBasicRemote().sendText(message);}} catch (Exception e) {e.printStackTrace();}}}/*** 給所有用戶*/public void sendAllUsers() {HashMap<String, List<WebSocketVO>> stringListHashMap = new HashMap<>(0);List<WebSocketVO> WebSocketVOs = new ArrayList<>();stringListHashMap.put("users", WebSocketVOs);for (Serializable key : SESSION_POOL.keySet()) {User user = userService.getById(key);WebSocketVO WebSocketVO = new WebSocketVO();BeanUtils.copyProperties(user, WebSocketVO);WebSocketVOs.add(WebSocketVO);}sendAllMessage(JSONUtil.toJsonStr(stringListHashMap));}
}
這是自己的代碼
package com.ruoyi.webSocket;import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.room.domain.Room;
import com.ruoyi.room.service.IRoomService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;@Component
@ServerEndpoint("/module/websocket/{userId}/{roomId}")
public class WebSocketServer implements ApplicationContextAware {private static IRoomService roomService;private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);// 保存隊伍的連接信息 - 新增private static final Map<String, ConcurrentHashMap<String, WebSocketServer>> ROOMS = new HashMap<>();//靜態變量,用來記錄當前在線連接數。應該把它設計成線程安全的。private static AtomicInteger onlineNum = new AtomicInteger();//concurrent包的線程安全Set,用來存放每個客戶端對應的WebSocketServer對象。private static ConcurrentHashMap<String, Session> sessionPools = new ConcurrentHashMap<>();// 線程安全list,用來存放 在線客戶端賬號public static List<String> userList = new CopyOnWriteArrayList<>();// 連接成功@OnOpenpublic void onOpen(Session session, @PathParam(value = "userId") String userId, @PathParam(value = "roomId") String roomId) {// 創建session給客戶sessionPools.put(userId, session);if (!userList.contains(userId)) {addOnlineCount();userList.add(userId);}try {if (StringUtils.isBlank(userId) || "undefined".equals(userId) ||StringUtils.isBlank(roomId) || "undefined".equals(roomId)) {sendError(userId, "參數有誤");return;}if (!ROOMS.containsKey(roomId)) {// 房間不存在 創建房間ConcurrentHashMap<String, WebSocketServer> room = new ConcurrentHashMap<>(0);room.put(userId, this);ROOMS.put(String.valueOf(roomId), room);} else {if (!ROOMS.get(roomId).containsKey(userId)) {// 房間存在 客戶不存在 房間加入客戶ROOMS.get(roomId).put(userId, this);}}log.debug("ID為【" + userId + "】的用戶加入websocket!當前在線人數為:" + onlineNum);log.debug("當前在線:" + userList);} catch (Exception e) {e.printStackTrace();}}/*** 關閉連接* @param userId*/@OnClosepublic void onClose(@PathParam(value = "userId") String userId) {sessionPools.remove(userId);if (userList.contains(userId)) {userList.remove(userId);subOnlineCount();}log.debug(userId + "斷開webSocket連接!當前人數為" + onlineNum);}/*** 消息監聽 接收客戶端消息* @param message* @throws IOException*/@OnMessagepublic void onMessage(String message) throws IOException {JSONObject jsonObject = JSONObject.parseObject(message);String userId = jsonObject.getString("userId");String roomId = jsonObject.getString("roomId");String type = jsonObject.getString("type");if (type.equals(MessageType.DETAIL.getType())) {log.debug("房間詳情");try {Room room = roomService.selectRoomById(Long.parseLong(roomId));jsonObject.put("roomInfo", room);ConcurrentHashMap<String, WebSocketServer> map = ROOMS.get(roomId);// 獲取玩家列表 keySet獲取map集合key的集合 然后在遍歷key即可for (String key : map.keySet()) {try {sendToUser(key, JSONObject.toJSONString(jsonObject));} catch (Exception e) {e.printStackTrace();}}} catch (NumberFormatException e) {System.out.println("轉換錯誤: " + e.getMessage());}}}/*** 連接錯誤* @param session* @param throwable* @throws IOException*/@OnErrorpublic void onError(Session session, Throwable throwable) throws IOException {log.error("websocket連接錯誤!");throwable.printStackTrace();}/*** 發送消息*/public void sendMessage(Session session, String message) throws IOException, EncodeException {if (session != null) {synchronized (session) {session.getBasicRemote().sendText(message);}}}/*** 給指定用戶發送信息*/public void sendToUser(String userId, String message) {Session session = sessionPools.get(userId);try {if (session != null) {sendMessage(session, message);}else {log.debug("推送用戶不在線");}} catch (Exception e) {e.printStackTrace();}}public static void addOnlineCount() {onlineNum.incrementAndGet();}public static void subOnlineCount() {onlineNum.decrementAndGet();}/*** 發送失敗** @param userId 用戶id* @param errorMessage 錯誤消息*/private void sendError(String userId, String errorMessage) {JSONObject obj = new JSONObject();obj.put("error", errorMessage);sendOneMessage(userId, obj.toString());}/*** 發送一個消息** @param userId 用戶編號* @param message 消息*/public void sendOneMessage(String userId, String message) {Session session = sessionPools.get(userId);if (session != null && session.isOpen()) {try {synchronized (session) {session.getBasicRemote().sendText(message);}} catch (Exception e) {e.printStackTrace();}}}
}
修改后的代碼
package com.ruoyi.webSocket;import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.room.domain.Room;
import com.ruoyi.room.service.IRoomService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;@Component
@ServerEndpoint("/module/websocket/{userId}/{roomId}")
public class WebSocketServer implements ApplicationContextAware {private static ApplicationContext context;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {context = applicationContext;}public static <roomService> roomService getBean(Class<roomService> beanClass) {return context.getBean(beanClass);}private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);// 保存隊伍的連接信息 - 新增private static final Map<String, ConcurrentHashMap<String, WebSocketServer>> ROOMS = new HashMap<>();//靜態變量,用來記錄當前在線連接數。應該把它設計成線程安全的。private static AtomicInteger onlineNum = new AtomicInteger();//concurrent包的線程安全Set,用來存放每個客戶端對應的WebSocketServer對象。private static ConcurrentHashMap<String, Session> sessionPools = new ConcurrentHashMap<>();// 線程安全list,用來存放 在線客戶端賬號public static List<String> userList = new CopyOnWriteArrayList<>();// 連接成功@OnOpenpublic void onOpen(Session session, @PathParam(value = "userId") String userId, @PathParam(value = "roomId") String roomId) {// 創建session給客戶sessionPools.put(userId, session);if (!userList.contains(userId)) {addOnlineCount();userList.add(userId);}try {if (StringUtils.isBlank(userId) || "undefined".equals(userId) ||StringUtils.isBlank(roomId) || "undefined".equals(roomId)) {sendError(userId, "參數有誤");return;}if (!ROOMS.containsKey(roomId)) {// 房間不存在 創建房間ConcurrentHashMap<String, WebSocketServer> room = new ConcurrentHashMap<>(0);room.put(userId, this);ROOMS.put(String.valueOf(roomId), room);} else {if (!ROOMS.get(roomId).containsKey(userId)) {// 房間存在 客戶不存在 房間加入客戶ROOMS.get(roomId).put(userId, this);}}log.debug("ID為【" + userId + "】的用戶加入websocket!當前在線人數為:" + onlineNum);log.debug("當前在線:" + userList);} catch (Exception e) {e.printStackTrace();}}/*** 關閉連接* @param userId*/@OnClosepublic void onClose(@PathParam(value = "userId") String userId) {sessionPools.remove(userId);if (userList.contains(userId)) {userList.remove(userId);subOnlineCount();}log.debug(userId + "斷開webSocket連接!當前人數為" + onlineNum);}/*** 消息監聽 接收客戶端消息* @param message* @throws IOException*/@OnMessagepublic void onMessage(String message) throws IOException {JSONObject jsonObject = JSONObject.parseObject(message);String userId = jsonObject.getString("userId");String roomId = jsonObject.getString("roomId");String type = jsonObject.getString("type");if (type.equals(MessageType.DETAIL.getType())) {log.debug("房間詳情");try {Room room = context.getBean(IRoomService.class).selectRoomById(Long.parseLong(roomId));jsonObject.put("roomInfo", room);ConcurrentHashMap<String, WebSocketServer> map = ROOMS.get(roomId);// 獲取玩家列表 keySet獲取map集合key的集合 然后在遍歷key即可for (String key : map.keySet()) {try {sendToUser(key, JSONObject.toJSONString(jsonObject));} catch (Exception e) {e.printStackTrace();}}} catch (NumberFormatException e) {System.out.println("轉換錯誤: " + e.getMessage());}}}/*** 連接錯誤* @param session* @param throwable* @throws IOException*/@OnErrorpublic void onError(Session session, Throwable throwable) throws IOException {log.error("websocket連接錯誤!");throwable.printStackTrace();}/*** 發送消息*/public void sendMessage(Session session, String message) throws IOException, EncodeException {if (session != null) {synchronized (session) {session.getBasicRemote().sendText(message);}}}/*** 給指定用戶發送信息*/public void sendToUser(String userId, String message) {Session session = sessionPools.get(userId);try {if (session != null) {sendMessage(session, message);}else {log.debug("推送用戶不在線");}} catch (Exception e) {e.printStackTrace();}}public static void addOnlineCount() {onlineNum.incrementAndGet();}public static void subOnlineCount() {onlineNum.decrementAndGet();}/*** 發送失敗** @param userId 用戶id* @param errorMessage 錯誤消息*/private void sendError(String userId, String errorMessage) {JSONObject obj = new JSONObject();obj.put("error", errorMessage);sendOneMessage(userId, obj.toString());}/*** 發送一個消息** @param userId 用戶編號* @param message 消息*/public void sendOneMessage(String userId, String message) {Session session = sessionPools.get(userId);if (session != null && session.isOpen()) {try {synchronized (session) {session.getBasicRemote().sendText(message);}} catch (Exception e) {e.printStackTrace();}}}
}
核心代碼
private static ApplicationContext context;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {context = applicationContext;}public static <roomService> roomService getBean(Class<roomService> beanClass) {return context.getBean(beanClass);}
Room room = context.getBean(IRoomService.class).selectRoomById(Long.parseLong(roomId));
原因:執行的先后順序吧,具體還沒仔細了解