1. Introduction
Based on Spring Boot and Websocket to achieve point-to-point online chat and simple robot automatic reply function, students can choose online idle teacher consultation, no online teacher access robot according to the content and question number of students to get the corresponding answer from the question library to reply to students.
2. The background
2.1. Introduce dependencies
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-websocket
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-websocket', version: '2.0.4.RELEASE'
Copy the code
2.2. Websocket configuration class
WebsocketConfig.java
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter(a) {
return newServerEndpointExporter(); }}Copy the code
2.3. Encapsulate display message objects
@Data
public class MessageVo {
@apiModelProperty (value = "user id")
private Integer userId;
@apiModelProperty (value = "username ")
private String username;
@apiModelProperty (value = "message content ")
private String msg;
@apiModelProperty (value = "number of people online ")
private int count;
}
Copy the code
2.4. Encapsulate the object of the conversation
The user information used to store the session
@Data
@apiModel (description = "webSocket session object ")
public class SocketUserInfo extends BaseEntity {
/ / user sessionId
private String sessionId;
/ / the user session
private Session session;
// Target user sessionID
private String targetSessionId;
// User role
private String userRole;
/ / user id
private Integer userId;
/ / user name
private String userName;
// Contact number
private String tel;
Copy the code
2.5. Websocket handling classes
@Slf4j
@Component
@ServerEndpoint(value = "/groupChat/{targetSessionId}/{userId}",configurator = SpringContextUtil.class)
public class WebSocketServerController{
// Use a local thread to save sessions
private static ThreadLocal<Session> sessions = new ThreadLocal<Session>();
// Save session sessionids of all connected users as keys
private static Map<String, SocketUserInfo> userSessionMap = new ConcurrentHashMap<>();
// Save the teacher's session
private static Map<String, SocketUserInfo> serverSessionMap = new ConcurrentHashMap<>();
// Save students online
private static List<Map<String,Object>> studentUserMapList = new ArrayList<>();
// Save the teacher information online
private static List<Map<String,Object>> teacherUserMapList = new ArrayList<>();
@Autowired
private CacheProxy cacheProxy;
@Autowired
private BuiProblemAnswerServiceImpl buiProblemAnswerService;
/** * set up the connection call method, group members join **@param session
* @paramTargetSessionId Session ID of the object consulted by the student */
@OnOpen
public void onOpen(Session session,
@PathParam("targetSessionId") String targetSessionId,
@PathParam("userId") Integer userId) {
try {
MessageVo messageVo = new MessageVo();
// Ensure that variables in each thread are relatively independent of variables in other threads
sessions.set(session);
// Get user information
SysLoginUserServiceImpl sysLoginUserService = SpringContextUtil.getBean(SysLoginUserServiceImpl.class);
Map<String, Object> map = sysLoginUserService.queryUserInfoById(userId);
// The teacher is online
if ("10000".equals(targetSessionId)){
// If you are the teacher and administrator, create an online chat message
SocketUserInfo serverInfo = new SocketUserInfo();
serverInfo.setUserRole("Teacher");
serverInfo.setSession(session);
serverInfo.setUserId(userId);
serverInfo.setSessionId(session.getId());
serverInfo.setUserName(StrUtil.clearNull(map.get("userName")));
serverInfo.setTerminalCode(StrUtil.clearNull(map.get("tel")));
map.put("sessionId",session.getId());
// Add teacher information to the list
teacherUserMapList.add(map);
// Write the online teacher information to the cache
cacheProxy.set("websocket",teacherUserMapList);
messageVo.setMsg(session.getId()+"You are online.");
messageVo.setUserId(userId);
sendMsg(session,messageVo);
// Save the teacher's information to map
serverSessionMap.put(session.getId(),serverInfo);
}
if (!"10000".equals(targetSessionId)){// Create an online student profile
SocketUserInfo userInfo = new SocketUserInfo();
userInfo.setSessionId(session.getId());
userInfo.setSession(session);
userInfo.setUserRole("Students");
userInfo.setUserId(userId);
userInfo.setUserName(StrUtil.clearNull(map.get("userName")));
userInfo.setTerminalCode(StrUtil.clearNull(map.get("tel")));
// Get the corresponding teacher information
if(! targetSessionId.equals("kefu")){
SocketUserInfo serverInfo = serverSessionMap.get(targetSessionId);
// Set the teacher's connection to the current student
serverInfo.setTargetSessionId(session.getId());
// Set the current student's connection object to the teacher
userInfo.setTargetSessionId(targetSessionId);
// Remove the currently consulted teacher from the free list
for (int i = 0; i < teacherUserMapList.size(); i++) {
Map<String, Object> teacherMap = teacherUserMapList.get(i);
if (teacherMap.get("sessionId").equals(targetSessionId)){ teacherUserMapList.remove(i); }}// Update the list of teachers available for consultation
cacheProxy.set("websocket",teacherUserMapList);
// Send a message to students
messageVo.setMsg("Teacher"+serverInfo.getUserName()+"Answering your questions!");
messageVo.setCount(2);
messageVo.setUserId(serverInfo.getUserId());
sendMsg(userInfo.getSession(), messageVo);
// Send a message to the teacher
messageVo.setMsg("For the students"+userInfo.getSessionId()+"Answer!");
messageVo.setUserId(userInfo.getUserId());
sendMsg(serverInfo.getSession(), messageVo);
}
if ("kefu".equals(targetSessionId)){
userInfo.setTargetSessionId("kefu");
messageVo.setMsg("Please enter the problem number according to the list on the right!!");
sendMsg(session,messageVo);
}
// Save online user information to mapuserSessionMap.put(session.getId(), userInfo); }}catch(Exception e){ e.printStackTrace(); }}/** * Group member sends message ** after receiving the method called by the message@param message
* @param session
*/
@OnMessage
public void onMessage(String message, Session session){
HashMap<String, String> result = new HashMap<>();
MessageVo messageVo = new MessageVo();
SocketUserInfo serverInfo = serverSessionMap.get(session.getId());
if(serverInfo ! =null) {// Teacher message
log.info("Teacher"+ session.getId()+"Send a message: \""+ message +"\" For students"+serverSessionMap.get(session.getId()).getTargetSessionId());
result.put("msg"."Teacher"+session.getId()+":"+message);
messageVo.setMsg(message);
messageVo.setUserId(serverInfo.getUserId());
messageVo.setCount(2);
// The message is passed to the student to determine if the student is bound to
if (null! = serverInfo.getTargetSessionId()){// Send the message to the bound student
sendMsg(userSessionMap.get(serverSessionMap.get(session.getId()).getTargetSessionId()).getSession(), messageVo);
}
sendMsg(session,messageVo);
} else {// Student information
System.out.println("Students"+ session.getId()+"Send a message: \""+ message +"\" To the teacher"+userSessionMap.get(session.getId()).getTargetSessionId());
result.put("msg"."Students"+session.getId()+":"+message);
messageVo.setCount(2);
messageVo.setMsg(message);
messageVo.setUserId(userSessionMap.get(session.getId()).getUserId());
// The student sends out a message
sendMsg(session,messageVo);
// Check whether the teacher is bound and send a message if so
String targetSessionId = userSessionMap.get(session.getId()).getTargetSessionId();
if (null! = targetSessionId && ! targetSessionId.equals("kefu")) {// Send a message to the teacher that the current student is consulting
messageVo.setUserId(userSessionMap.get(session.getId()).getUserId());
sendMsg(serverSessionMap.get(userSessionMap.get(session.getId()).getTargetSessionId()).getSession(), messageVo);
}
if (null! = targetSessionId && targetSessionId.equals("kefu")) {try {
Long problemNumber = Long.valueOf(StrUtil.clearNull(message));
String answer = buiProblemAnswerService.getAnswer(problemNumber);
messageVo.setMsg(answer);
if (answer == null){
messageVo.setMsg("Please enter the correct problem number!!"); }}catch (Exception e){
List<BuiProblemAnswer> buiProblemAnswerList = buiProblemAnswerService.getAnswerList(message);
if (buiProblemAnswerList.size() > 1){
String msg = "Guess what you want to ask: \t";
for (BuiProblemAnswer buiProblemAnswer : buiProblemAnswerList) {
msg = msg + buiProblemAnswer.getProblemTopic()+"\t";
}
messageVo.setMsg(msg);
}else if (buiProblemAnswerList.size() == 1){
messageVo.setMsg(buiProblemAnswerList.get(0).getProblemAnswer());
}else if (buiProblemAnswerList.size() == 0){
messageVo.setMsg("I'm sorry! Didn't find your problem!");
}
// messagevo. setMsg(" guess what you want to ask :\t"+);
// messagevo. setMsg(" Please enter the correct problem number!! ") );}}// Reply to student messages
messageVo.setUserId(null); sendMsg(session,messageVo); }}/** * Closes the method called by the connection, and the group member exits@param session
* @param targetSessionId
*/
@OnClose
public void onClose(Session session, @PathParam("targetSessionId") String targetSessionId, @PathParam("userId") Integer userId) {
SocketUserInfo serverInfo = serverSessionMap.get(session.getId());
MessageVo messageVo = new MessageVo();
if(serverInfo ! =null) {// Remove the teacher from the map
for (int i = 0; i < teacherUserMapList.size(); i++) {
Map<String, Object> map = teacherUserMapList.get(i);
if (userId == map.get("userId")){ teacherUserMapList.remove(i); }}// Update the cached data of the online teacher
cacheProxy.set("websocket",teacherUserMapList);
serverSessionMap.remove(session.getId());
// Check whether there are currently serving objects and send system error messages to the user if there are
if(serverInfo.getTargetSessionId() ! =null){
messageVo.setMsg("System error. The teacher has been logged out.");
messageVo.setUserId(serverInfo.getUserId());
sendMsg(userSessionMap.get(serverInfo.getTargetSessionId()).getSession(),messageVo);
}
log.info("Teacher No. : + session.getId() + "Quit connection, current online teacher total:" + serverSessionMap.size());
}else if ("10000".equals(targetSessionId)){
// If there are still students waiting in the queue, bind the student to the current teacher
userSessionMap.remove(session.getId());
// Get the current teacher information
SocketUserInfo serverUserInfo = serverSessionMap.get(targetSessionId);
HashMap<String, Object> teacherMap = new HashMap<>();
teacherMap.put("userName",serverUserInfo.getUserName());
teacherMap.put("serssionId",serverUserInfo.getSessionId());
teacherMap.put("tel",serverUserInfo.getTerminalCode());
teacherMap.put("userId",serverUserInfo.getUserId());
// Add the current teacher to the free teacher list and update the cache
teacherUserMapList.add(teacherMap);
cacheProxy.set("websocket",teacherUserMapList);
log.info("User Id:" + session.getId() + "Disconnected, current online students total:"+ userSessionMap.size()); }}/** * Transfer message error called method **@param error
*/
@OnError
public void OnError(Throwable error) {
log.info("Connection error");
}
// Query queued users
private synchronized String findLineUser(a){
// Check whether there are users
if (userSessionMap.size() > 0) {// Iterate over all users to find a queued user
for (SocketUserInfo UserInfo: userSessionMap.values()) {
if (null == UserInfo.getTargetSessionId()){
returnUserInfo.getSessionId(); }}}return null;
}
// Query available teachers online
private synchronized String findFreeServer(a){
// Check if there is a teacher
if (serverSessionMap.size() > 0) {// Walk through all the teachers online to find a free teacher
for (SocketUserInfo serverInfo: serverSessionMap.values()) {
if (null == serverInfo.getTargetSessionId()){
returnserverInfo.getSessionId(); }}}return null;
}
// Unified message sending method
private synchronized void sendMsg(Session session, MessageVo messageVo) {
try {
session.getBasicRemote().sendText(JSON.toJSONString(messageVo));
} catch(IOException e) { e.printStackTrace(); }}}Copy the code
Can’t inject bean instance in websocket
This allows you to inject instances using @AutoWired
Finally, the front-end can use ‘ws:// IP address: port/item address /groupChat/{parameter 1}/{parameter 2}’ to request a connection
Note: If user authentication is performed in the background and an interceptor is configured, the interface needs to be allowed