栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringBoot开发网页即时聊天室/IM通信/WebSocket/即时通讯

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringBoot开发网页即时聊天室/IM通信/WebSocket/即时通讯

现在的java开发基本都是基于springboot,所以我们就基于springboot2环境。

效果展示(基于网页浏览器的,不是桌面程序)

通讯协议:

现在的主流浏览器基本都支持html5标准,所以我们就用websocket作为通信协议。

后端框架:

后端采用springboot作为主框架,配合websocket模块与前端通信,通过springboot整合redis,mybatis,mysql。

消息中转:

使用redis的订阅发布机制作为消息中转,实现消息的顺序消费,即保证数据的实时性,也保证数据的安全性。

聊天方式:

单人聊天,多人群聊,

离线消息:

当群聊时,或者单人聊天时,如果对方不在线,则记录离线消息,当对方上线时会统一接收。

代码参考

redis配置

@Configuration
public class RedisConfig {

    
    @Bean
    RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
                                            MessageListenerAdapter listenerAdapter) {

        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        //订阅了一个叫chat 的通道
        container.addMessageListener(listenerAdapter, new PatternTopic("chat"));
        //这个container 可以添加多个 messageListener
        return container;
    }

    
    @Bean
    MessageListenerAdapter listenerAdapter(RedisReceiver receiver) {
        //这个地方 是给messageListenerAdapter 传入一个消息接受的处理器,利用反射的方法调用“receiveMessage”
        //也有好几个重载方法,这边默认调用处理器的方法 叫handleMessage 可以自己到源码里面看
        return new MessageListenerAdapter(receiver, "receiveMessage");
    }

    
    @Bean(name="stringRedisTemplate")
    StringRedisTemplate template(RedisConnectionFactory connectionFactory) {
        return new StringRedisTemplate(connectionFactory);
    }

}

消息中转器

@EnableScheduling
@Component
public class RedisReceiver {

    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    UserDao userDao;
    @Autowired
    RecordDao recordDao;

    public static class SessionInfo {
        public Session session;
        public long userid;
        public SessionInfo(Session session, long userid) {
            this.session = session;
            this.userid = userid;
        }
    }

    ObjectMapper objectMapper = new ObjectMapper();

    public List list = new LinkedList();

    public void onOpen(Session session, long userid){
        if(isUserOnline(userid)){
            try {
                System.out.println("已经在线");
                send(session,"已经在线");
                session.close();
                return;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        synchronized (list) {
            list.add(new SessionInfo(session,userid));
            System.out.println("有人上线了:"+list.size());
            stringRedisTemplate.opsForValue().setBit("ONLINE", userid, true);
            sendOnlineOrOffline(userid,"online");
        }

        //推送离线消息
        List records=recordDao.findUnread(userid);
        records.forEach(record -> {
            try {
                sendToUserid(userid,record.getContent());
                record.setUsed(true);
                recordDao.save(record);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

}

用户模型

@Data
@Entity
@Table(name="im_user")
public class User {
    @Id@GeneratedValue
    private Long id;
    private String username;
    private String sign;
    private String status;
    private String avatar;
    private Date created;
    private String password;
}

消息记录

@Data
@Entity
@Table(name="im_record")
public class Record {
    @Id
    @GeneratedValue
    private Long id;
    @Column(columnDefinition = "TEXT")
    private String content;
    private Date created;
    @Column(name = "from_user_id")
    private Long from;
    @Column(name = "to_user_id")
    private Long to;
    private Boolean used; //是否已经读取过,true代表读取过,false代表未读

}

群组聊天

@Data
@Entity
@Table(name="im_group")
public class Group {

    @Id
    @GeneratedValue
    private Long id;
    private String name;
    private Date created;

    @ManyToOne()
    @JoinColumn(name="user_id")
    private User user;  //此分组的主人

    @ManyToMany()
    @JoinTable(name="im_group_user",
            joinColumns = {@JoinColumn(name="group_id")}, //连接本类
            inverseJoinColumns = {@JoinColumn(name="user_id")})//连接此属性的类
    private List list; //分组中的好友
}

使用redis的优势

  • 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
  • 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
  • 原子 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
  • 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。

参考链接 完整项目参考链接点击这里

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1023937.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号