pom.xml文件添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
WebSocketConfig
import com.common.config.MyEndpointConfigure;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* WebSocket配置
* @Author JYuan
*/
@Configuration
public class WebSocketConfig{
/**
* 用途:扫描并注册所有携带@ServerEndpoint注解的实例。 @ServerEndpoint("/websocket")
* PS:如果使用外部容器 则无需提供ServerEndpointExporter。
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
/**
* 支持注入其他类
*/
@Bean
public MyEndpointConfigure myEndpointConfigure(){
return new MyEndpointConfigure();
}
}
MyEndpointConfigure
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import javax.websocket.server.ServerEndpointConfig;
/**
* @Author JYuan
*/
public class MyEndpointConfigure extends ServerEndpointConfig.Configurator implements ApplicationContextAware {
private static volatile BeanFactory context;
@Override
public <T> T getEndpointInstance(Class<T> clazz){
return context.getBean(clazz);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
MyEndpointConfigure.context = applicationContext;
}
}
WebSocketServer
import com.alibaba.fastjson.JSONObject;
import com.common.config.MyEndpointConfigure;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* WebSocket服务
* @Author JYuan
*/
@RestController
@RequestMapping("/websocket")
@ServerEndpoint(value = "/websocket/{userNo}", configurator = MyEndpointConfigure.class)
public class WebSocketServer {
/**
* 在线人数
*/
private static int onlineCount = 0;
/**
* 在线用户的Map集合,key:用户名,value:Session对象
*/
private static Map<String, Session> sessionMap = new HashMap<>();
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session, @PathParam("userNo") String userNo {
//在webSocketMap新增上线用户
sessionMap.put(userNo, session);
//在线人数加加
WebSocketServer.onlineCount++;
//通知除了自己之外的所有人
sendOnlineCount(session, "{'type':'onlineCount','onlineCount':" + WebSocketServer.onlineCount + ",username:'" + username + "'}");
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose(Session session, @PathParam("userType") String userType) {
//下线用户名
String logoutUserName = "";
//从webSocketMap删除下线用户
for (Map.Entry<String, Session> entry : sessionMap.entrySet()) {
if (entry.getValue() == session) {
sessionMap.remove(entry.getKey());
logoutUserName = entry.getKey();
break;
}
}
//在线人数减减
WebSocketServer.onlineCount--;
//通知除了自己之外的所有人
sendOnlineCount(session, "{'type':'onlineCount','onlineCount':" + WebSocketServer.onlineCount + ",username:'" + logoutUserName + "'}");
}
/**
* 服务器接收到客户端消息时调用的方法
*/
@OnMessage
public void onMessage(String message, Session session) {
try {
//JSON字符串转 HashMap
HashMap hashMap = new ObjectMapper().readValue(message, HashMap.class);
//消息类型
String type = (String) hashMap.get("type");
//来源用户
Map srcUser = (Map) hashMap.get("srcUser");
//目标用户
Map tarUser = (Map) hashMap.get("tarUser");
//如果点击的是自己,那就是群聊
if (srcUser.get("userNo").equals(tarUser.get("userNo"))) {
//群聊
groupChat(session,hashMap);
} else {
//私聊
privateChat(session, tarUser, hashMap);
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 发生错误时调用
*/
@OnError
public void onError(Throwable e){
e.printStackTrace();
}
/**
* 通知除了自己之外的所有人
*/
private void sendOnlineCount(Session session, String message) {
for (Map.Entry<String, Session> entry : sessionMap.entrySet()) {
try {
if (entry.getValue() != session) {
entry.getValue().getBasicRemote().sendText(message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 私聊
*/
private void privateChat(Session session, Map tarUser, HashMap hashMap) throws IOException {
//获取目标用户的session
Session tarUserSession = sessionMap.get(tarUser.get("userNo"));
//如果不在线则发送“对方不在线”回来源用户
if (tarUserSession == null) {
session.getBasicRemote().sendText("{\"type\":\"0\",\"message\":\"对方不在线\"}");
} else {
hashMap.put("type", "1");
tarUserSession.getBasicRemote().sendText(new ObjectMapper().writeValueAsString(hashMap));
}
}
/**
* 群聊
*/
private void groupChat(Session session,HashMap hashMap) throws IOException {
for (Map.Entry<String, Session> entry : sessionMap.entrySet()) {
//自己就不用再发送消息了
if (entry.getValue() != session) {
hashMap.put("type", "2");
entry.getValue().getBasicRemote().sendText(new ObjectMapper().writeValueAsString(hashMap));
}
}
}
/**
* 登录
*/
public ModelAndView login(HttpServletRequest request, @PathVariable String userNo, @PathVariable String userType) {
return new ModelAndView("socketChart.html", "userNo", userNo);
}
/**
* 登出
*/
public String loginOut(HttpServletRequest request, @PathVariable String userNo) {
return "退出成功!";
}
/**
* 获取在线用户
*/
@PostMapping("/getOnlineList")
private List<String> getOnlineList(@RequestBody JSONObject requestJson) {
String userNo = requestJson.getString("userNo");
List<String> list = new ArrayList<>();
//遍历webSocketMap
for (Map.Entry<String, Session> entry : WebSocketServer.sessionMap.entrySet()) {
if (!entry.getKey().equals(userNo)) {
list.add(entry.getKey());
}
}
return list;
}
}
其他问题
项目启动报错
Registering @ServerEndpoint class: class com.cxy.common.controller.WebSocketServer$$EnhancerBySpringCGLIB$$badc049a
问题是EnhancerBySpringCGLIB,可以看出来,使用了CGLIB代理,那么问题就很明显了,此类被AOP做了代理,在AOP中将此类移除就可以了。
@Pointcut("execution(* com.*.controller..*(..)) && !execution(* com.common.controller.WebSocketServer.*(..))")
public void aspect() {
}