websocket的使用

1.引入依赖

java 复制代码
<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-websocket</artifactId>

</dependency>

2.配置websocket服务

java 复制代码
@Configuration
public class WebSocketConfig {

    /**
     * 配置WebSocket服务
     * @return
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }
}

3.启动类添加注解

java 复制代码
@EnableWebSocket

4.websocket服务端逻辑

java 复制代码
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * WebSocketServer服务端
 */
@Slf4j
@Component
@ServerEndpoint("/websocket/{uid}")
public class WebSocketClient {
    /**
     * 静态变量,用来记录当前在线连接数,线程安全的类。
     */
    private static AtomicInteger onlineSessionClientCount = new AtomicInteger(0);
    /**
     * 存放所有在线的客户端
     */
    private static Map<String, Session> onlineSessionClientMap = new ConcurrentHashMap<>();

    /**
     * 连接uid和连接会话
     */
    private String uid;
    private Session session;


    /**
     * 连接建立成功调用的方法。由前端<code>new WebSocket</code>触发
     *
     * @param uid     每次页面建立连接时传入到服务端的id,比如用户id等。可以自定义。
     * @param session 与某个客户端的连接会话,需要通过它来给客户端发送消息
     */
    @OnOpen
    public void onOpen(@PathParam("uid") String uid, Session session) {
        /**
         * session.getId():当前session会话会自动生成一个id,从0开始累加的。
         */
        log.info("连接建立中 ==> session_id = {}, sid = {}", session.getId(), uid);
        //加入 Map中。将页面的uid和session绑定或者session.getId()与session
        //onlineSessionIdClientMap.put(session.getId(), session);
        onlineSessionClientMap.put(uid, session);
        //在线数加1
        onlineSessionClientCount.incrementAndGet();
        this.uid = uid;
        this.session = session;
        sendToOne(uid, "连接成功");
        log.info("连接建立成功,当前在线数为:{} ==> 开始监听新连接:session_id = {}, sid = {},。", onlineSessionClientCount, session.getId(), uid);
    }

    /**
     * 连接关闭调用的方法。由前端<code>socket.close()</code>触发
     *
     * @param uid
     * @param session
     */
    @OnClose
    public void onClose(@PathParam("uid") String uid, Session session) {
        //onlineSessionIdClientMap.remove(session.getId());
        // 从 Map中移除
        onlineSessionClientMap.remove(uid);

        //在线数减1
        onlineSessionClientCount.decrementAndGet();
        log.info("连接关闭成功,当前在线数为:{} ==> 关闭该连接信息:session_id = {}, sid = {},。", onlineSessionClientCount, session.getId(), uid);
    }

    /**
     * 收到客户端消息后调用的方法。由前端<code>socket.send</code>触发
     * * 当服务端执行toSession.getAsyncRemote().sendText(xxx)后,前端的socket.onmessage得到监听。
     *
     * @param message
     * @param session
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        /**
         * html界面传递来得数据格式,可以自定义.
         * {"sid":"user-1","message":"hello websocket"}
         */
        log.info("接收到消息-----------------"+message);
        List<String> uids = session.getRequestParameterMap().get("uid");
        for (String uid : uids) {
            // 接收前端拖推送改的消息
            sendToOne(uid, "来自服务端的推送=====》你好前端! 我已经成功收到消息!消息数据为:" + message);
        }
    }

    /**
     * 发生错误调用的方法
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("WebSocket发生错误,错误信息为:" + error.getMessage());
        error.printStackTrace();
    }

    /**
     * 群发消息
     *
     * @param message 消息
     */
    public void sendToAll(String message) {
        // 遍历在线map集合
        onlineSessionClientMap.forEach((onlineSid, toSession) -> {
            // 排除掉自己
            if (!uid.equalsIgnoreCase(onlineSid)) {
                log.info("服务端给客户端群发消息 ==> sid = {}, toSid = {}, message = {}", uid, onlineSid, message);
                toSession.getAsyncRemote().sendText(message);
            }
        });
    }

    /**
     * 指定发送消息
     *
     * @param toUid
     * @param message
     */
    public boolean sendToOne(String toUid, String message) {
        /*
         * 判断发送者是否在线
         */
        Session toSession = onlineSessionClientMap.get(toUid);
        if (toSession == null) {
            log.error("服务端给客户端发送消息 ==> toSid = {} 不存在, message = {}", toUid, message);
            return false;
        }
        // 异步发送
        log.info("服务端给客户端发送消息 ==> toSid = {}, message = {}", toUid, message);
        toSession.getAsyncRemote().sendText(message);
        return true;
    }

}

5.service层调用推送消息方法

java 复制代码
@Service
public class WebSocketHandler {

    @Resource
    private WebSocketClient webSocketClient;

    public boolean sendMessageOne(String userId,String content) {
        boolean flag = webSocketClient.sendToOne(userId,content);
        return flag;
    }
}

6.controller层逻辑

java 复制代码
@PostMapping("/send")
    public Map push2(@RequestBody PushDTO pushDTO){
        Map map = new HashMap();
        //1、参数校验,非空~
        if(StringUtils.isEmpty(pushDTO.getMessage()) || pushDTO.getUserId() == null || pushDTO.getPushType() == null )    {
            log.info("【消息推送】 参数异常");
            map.put("code","-1");
            map.put("msg","参数异常");
            return map;
        }

        
        //2、推送消息
        boolean flag = webSocketHandler.sendMessageOne(pushMessage.getUserId() + "", content);
        //3、如果推送成功,修改状态,返回正确的JSON
        if(flag){
            PushMessage updatePushMessage = new PushMessage();
            updatePushMessage.setId(pushMessage.getId());
            updatePushMessage.setPushState(PUSH_SUCCESS);
//            pushMessageService.updateById(updatePushMessage);
            map.put("code","200");
            map.put("msg","成功");
            return map;
        }

        //4、返回用户未上线的JSON
        map.put("code","500");
        map.put("msg","用户离线");
        return map;

    }
相关推荐
黑客Ash1 小时前
计算机中的网络安全
网络·安全·web安全
PersistJiao1 小时前
Spark 分布式计算中网络传输和序列化的关系(二)
大数据·网络·spark·序列化·分布式计算
岳不谢2 小时前
VPN技术-VPN简介学习笔记
网络·笔记·学习·华为
Lws2 小时前
CS144 lab0(个人理解)
网络协议
follycat2 小时前
信息收集--CDN绕过
网络·安全·网络安全
宛唐羁客3 小时前
ODBC连接PostgreSQL数据库后,网卡DOWN后,客户端进程阻塞问题解决方法
网络·数据库
Beekeeper&&P...4 小时前
web钩子什么意思
前端·网络
vener_4 小时前
LuckySheet协同编辑后端示例(Django+Channel,Websocket通信)
javascript·后端·python·websocket·django·luckysheet
清风.春不晚5 小时前
shell脚本2---清风
网络·网络安全
枫叶丹45 小时前
【在Linux世界中追寻伟大的One Piece】手写序列化与反序列化
linux·运维·网络