• websocket使用sendObject产生的问题


    1. 问题

    当在使用WebSocket服务端向客户端发送消息时使用sendObject的方式传递信息出现了以下这个错误

    javax.websocket.EncodeException: No encoder specified for object of class
    
    • 1

    2. 原因

    这个错误的原因是当我们使用sendObject方式传递信息时需要指定对应的编码器对传递信息进行编码,编码器的设置就在@ServerEndpoint注解上。

    原先的@ServerEndpoint注解内容:

    @ServerEndpoint("/api/websocket/client/{clientId}")
    
    • 1

    只设定了默认的value值,编码器需要加入encoders属性,如下:

    @ServerEndpoint(value = "/api/websocket/client/{clientId}",encoders = {ServerEncoder.class})
    
    • 1

    3. 解决方案

    @ServerEndpoint注解上加入指定编码器类:

    @ServerEndpoint(value = "/api/websocket/client/{clientId}",encoders = {ServerEncoder.class})
    
    • 1

    encoders的属性是个数组,所以可以指定多个编码器编码器的泛型需要指定,如果发送消息的实体结构没有适合的编码器则会报上面的错误。

    3.1 HashMap编码类

    这是一个HashMap的编码类,将HashMap转为了序列化后的JSON字符串,核心就是encode方法,只需要返回Object序列化后的json字符串就行,这里使用的fastjson,也可以自定义其他序列化工具来进行序列化操作。

    import com.alibaba.fastjson.JSONObject;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import javax.websocket.EncodeException;
    import javax.websocket.Encoder;
    import javax.websocket.EndpointConfig;
    import java.util.HashMap;
    
    /**
     * @author YUSHENGDADA
     * @title: ServerEncoder
     * @projectName v2_lab
     * @description: WebSocket编码器
     * @date 2022/8/22 0022上午 11:42
     */
    public class HashMapEncoder implements Encoder.Text<HashMap> {
        private static final Logger log = LoggerFactory.getLogger(HashMapEncoder.class);
    
        /**
         * 这里的参数 hashMap 要和  Encoder.Text保持一致
         * @param hashMap
         * @return
         * @throws EncodeException
         */
        @Override
        public String encode(HashMap hashMap) throws EncodeException {
            /*
             * 这里是重点,只需要返回Object序列化后的json字符串就行
             * 你也可以使用gosn,fastJson来序列化。
             * 这里我使用fastjson
             */
            try {
                return JSONObject.toJSONString(hashMap);
            }catch (Exception e){
                log.info("ServerEncoder编码异常:{}",e.getMessage());
            }
            return null;
        }
    
        @Override
        public void init(EndpointConfig endpointConfig) {
            //可忽略
        }
    
        @Override
        public void destroy() {
            //可忽略
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    3.2 实体编码类

    在应用场景中直接使用HashMap传递参数还是不太优雅不好维护,所以这里再提供一个实体编码类,消息传递实体可以固定,业务实体作为其中data数据的内容

    3.2.1 消息实体
    @Data
    public class BaseInfoModel<T> {
    
        private String code;
        private String msg;
        private T data;
        
        public static <T> BaseResponseMessage success(T data) {
            BaseResponseMessage baseResponseMessage = new BaseResponseMessage();
            baseResponseMessage.code = "0";
            baseResponseMessage.msg = "成功";
            baseResponseMessage.data = data;
            return baseResponseMessage;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    3.2.2 实体编码类
    import com.an.websocket.model.client.BaseResponseMessage;
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.json.JsonMapper;
    
    import javax.websocket.EncodeException;
    import javax.websocket.Encoder;
    import javax.websocket.EndpointConfig;
    
    /**
     * @author YUSHENGDADA
     * @title: BaseModelEncoder
     * @projectName v2_lab
     * @description: 实体编码器
     * @date 2022/8/22 0022下午 14:15
     */
    public class BaseModelEncoder  implements Encoder.Text<BaseResponseMessage> {
        @Override
        public String encode(BaseResponseMessage baseResponseMessage) throws EncodeException {
            try {
                JsonMapper jsonMapper = new JsonMapper();
                return jsonMapper.writeValueAsString(baseResponseMessage);
    
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        @Override
        public void init(EndpointConfig endpointConfig) {
    
        }
    
        @Override
        public void destroy() {
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    3.2.3 注解配置

    实体跟实体编码器配置好后加入到注解的属性上,因为是数组直接HashMap的编码器后加入即可。

    代码如下:

    @ServerEndpoint(value = "/api/websocket/client/{clientId}",encoders = {HashMapEncoder.class, BaseModelEncoder.class})
    
    • 1

    发送消息的代码

    @OnMessage
    public void onMessage(String message, Session session,@PathParam("clientId") String clientId){
        UserMessageModel userMessageModel = JSONObject.parseObject(message, UserMessageModel.class);
        log.info("客户端:{} 发送到客户端:{},消息内容:{}",clientId,userMessageModel.getAcceptId(),userMessageModel.getMessage());
        webSocketClientMap.get(userMessageModel.getAcceptId()).sendMessage(BaseResponseMessage.success(userMessageModel));
    }
    
    private void  sendMessage(Object message){
        try {
            this.infoSession.getBasicRemote().sendObject(message);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (EncodeException e) {
            throw new RuntimeException(e);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    3.2.4 验证效果

    在客户端将收到的消息打印了出来,丑了点,凑合看,结构没问题就行

    在这里插入图片描述

  • 相关阅读:
    【JMeter】定时器分类以及场景介绍
    Flutter笔记:桌面应用 窗口定制库 bitsdojo_window
    零代码编程:用ChatGPT批量将Mp4视频转为Mp3音频
    嵌入式单片机智能药盒设计(含代码)
    如何在排除子目录时挂载 Docker 卷
    Audacity降噪消除视频中杂音
    PMP每日一练 | 考试不迷路-11.19(包含敏捷+多选)
    阿里云视频点播服务视频地址浏览器打开失效问题记录
    实现常规厂家&品牌&型号业务对接物联网平台(snack3加json赋能)
    攻防世界----easytornado笔记
  • 原文地址:https://blog.csdn.net/AnNanDu/article/details/126464531