SpringBoot开发网页即时聊天室/IM通信/WebSocket/即时通讯
SpringBoot开发网页即时聊天室/IM通信/WebSocket/即时通讯
·
现在的java开发基本都是基于springboot,所以我们就基于springboot2环境。
效果展示(基于网页浏览器的,不是桌面程序)
通讯协议:
现在的主流浏览器基本都支持html5标准,所以我们就用websocket作为通信协议。
后端框架:
后端采用springboot作为主框架,配合websocket模块与前端通信,通过springboot整合redis,mybatis,mysql。
消息中转:
使用redis的订阅发布机制作为消息中转,实现消息的顺序消费,即保证数据的实时性,也保证数据的安全性。
聊天方式:
单人聊天,多人群聊,
离线消息:
当群聊时,或者单人聊天时,如果对方不在线,则记录离线消息,当对方上线时会统一接收。
代码参考
redis配置
@Configuration
public class RedisConfig {
/**
* redis消息监听器容器
* 可以添加多个监听不同话题的redis监听器,只需要把消息监听器和相应的消息订阅处理器绑定,该消息监听器
* 通过反射技术调用消息订阅处理器的相关方法进行一些业务处理
* @param connectionFactory
* @param listenerAdapter
* @return
*/
@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;
}
/**
* 消息监听器适配器,绑定消息处理器,利用反射技术调用消息处理器的业务方法
* @param receiver
* @return
*/
@Bean
MessageListenerAdapter listenerAdapter(RedisReceiver receiver) {
//这个地方 是给messageListenerAdapter 传入一个消息接受的处理器,利用反射的方法调用“receiveMessage”
//也有好几个重载方法,这边默认调用处理器的方法 叫handleMessage 可以自己到源码里面看
return new MessageListenerAdapter(receiver, "receiveMessage");
}
/**redis 读取内容的template */
@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<SessionInfo> 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<Record> 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<User> list; //分组中的好友
}
使用redis的优势
- 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
- 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
- 原子 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
- 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。
参考链接 完整项目参考链接点击这里
更多推荐
已为社区贡献2条内容
所有评论(0)