• 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 验证效果

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

    在这里插入图片描述

  • 相关阅读:
    Linux软件包管理— 源码包的安装和卸载
    分库分表必会-跨库分页查询看此一篇就够了
    K8S:K8S自动化运维容器Docker集群
    我的创作纪念日,记录 Day,散
    低代码助力生产管理:车间管理系统
    QTabWidget 类 (选项卡部件)
    【C++】标准流与命名空间简介 ( Visual Studio 2019 中创建 C++ 项目 | iostream 标准流 | std 标准命名空间 | cout 控制台输出 )
    只需要改造一下实体类,以后再也不用写SQL了
    Oracle AutoVue 21.0.x最新支持程序文件格式及版本
    Lidar & IMU & GNSS in ENU
  • 原文地址:https://blog.csdn.net/AnNanDu/article/details/126464531