Vue+Spring Boot前后端分离集成websocket

背景

易登官网在前期为了快速为开发者提供服务,登录认证的时候使用轮询的方式,一遍遍调用后端接口判断用户是否已经登录。轮询的优点就是技术门槛低、开发方便,但是缺点也显而易见:频繁请求后端接口会占用大量服务器资源,也会让其他开发者看起来太不专业。

spring boot集成websocket

引入Maven依赖


	org.springframework.boot
	spring-boot-starter-websocket

配置websocket

  1. 在启动类上加注解:@EnableWebSocket
  2. 配置websocket Bean,该Bean会将所有@ServerEndpoint注解的类添加到webSocket容器中
@Configuration
public class WebSocketConfig {

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

webSocket服务类

@Slf4j
@ServerEndpoint(value = "/websocket/{userId}")
@Component
public class MyWebSocket {

    /**
     * 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
     */
    private static int onlineCount = 0;

    // 用来存放用户与会话的关系
    private static ConcurrentHashMap socketMap = new ConcurrentHashMap<>();

    /**
     * 与某个客户端的连接会话,需要通过它来给客户端发送数据
     */
    private Session session;

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        this.session = session;
        if (socketMap.containsKey(userId)) {
            socketMap.remove(userId);
            socketMap.put(userId, this);
        } else {
            socketMap.put(userId, this);
            //在线数加1
            addOnlineCount();
        }

        log.info("有新连接加入!userId={}, 当前在线人数为:{}", userId, getOnlineCount());
        try {
            sendMessage("success");
            log.info("新建链接成功");
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(@PathParam("userId") String userId) {
        socketMap.remove(userId);
        subOnlineCount();           //在线数减1
        log.info("有一连接关闭!当前在线人数为:{}", getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) throws IOException {
        log.info("收到客户端消息:{}", message);
    }

    // 给指定人发送消息
    public static void sendMessage(@PathParam("userId") String userId, String message) {
        MyWebSocket myWebSocket = socketMap.get(userId);
        if (myWebSocket != null) {
            try {
                myWebSocket.session.getBasicRemote().sendText(message);
            } catch (IOException e) {
                log.error("给用户:{}发送消息{}失败!", userId, message, e);
            }
        } else {
            log.warn("用户{}还未建立连接", userId);
        }
    }

    /**
     * 发生错误时调用
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发送消息失败!", error);
    }


    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
        //this.session.getAsyncRemote().sendText(message);
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        MyWebSocket.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        MyWebSocket.onlineCount--;
    }
}

vue使用webSocket

let ws = new WebSocket("ws://www.test.com/api/websocket/" + this.tempUserId);

// 创建连接成功回调
ws.onopen = () => {
	ws.send("连接成功");
}

// 关闭连接回调
ws.onclose = () => {

}

// 接收到服务端消息回调
ws.onmessage = (evt) => {
	let message = evt.data;
	console.log("收到ws消息:", message);
}

Nginx配置

# webSocket变量定义
map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

server {
	listen 80;
	server_name www.test.com;

	location / {
		root /var/html; # 前端静态页面路径
		index index.html;
	}

	location /api {
		proxy_pass http://localhost:8888;

		# 以下三行代码是升级请求协议,使之支持webSocket
		proxy_http_version 1.1;
	        proxy_set_header Upgrade $http_upgrade; # 主要配置
   		proxy_set_header Connection $connection_upgrade; #主要配置
	}
}

效果

用户在点击易登登录按钮后,前端与服务端建立ws连接

Vue+Spring Boot前后端分离集成websocket

用户在登录之后,服务端会给前端发送用户已经登录的消息,并将用户信息通过消息发送给前端页面

原文链接:记忆旅途

后端   Spring   Vue
发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章