目录
一、实现聊天室原理
二、聊天室前端代码
三、聊天室后端代码(重点)
四、聊天室实现效果展示
1.1 介绍websocket协议
websocket是一种通信协议,再通过websocket实现弹幕聊天室时候,实现原理是客户端首先使用http协议请求服务器将通信协议转为websocket协议。
1.2、websocket的API
websocket分为客户端与服务器,其实现的API都不一样。
前端创建websocket案例:
1.3 项目实现流程
1.4 项目结构
前端核心在于两个:一个登陆界面,一个聊天室界面。
登陆界面:
聊天室-登录
聊天室
登录
效果:
聊天室页面:
黑马畅聊-登录
聊天室
登录
3.1首先需要创建springboot项目,并导入以下jar包.
com.alibaba
fastjson
1.2.78
org.springframework.boot
spring-boot-starter-websocket
3.2 实现websocket,还需要对其进行配置,创建两个配置类
第一个进行websocketConfig的配置
@Configuration
public class WebsocketConfig {
// 将ServerEndPointExplorer加入ioc容器中
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
第二个配置是获取httpsession配置
public class GetHttpSessionConfig extends ServerEndpointConfig.Configurator {
@Override
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
//获取HttpSession对象
HttpSession httpSession = (HttpSession) request.getHttpSession();
//将httpSession对象保存起来
sec.getUserProperties().put(HttpSession.class.getName(),httpSession);
}
}
项目中需要ServerEndPoint存储所有用户的session对象,通过session实现用户之间的交流。所以还需要获取所有httpsession对象。
3.3 确定消息格式(JSON)
为了确保实现的消息格式的准确,需要创建对应工具类,确保对应的格式的准确。
public class MessageUtils {
public static String getMessage(boolean isSystemMessage,String fromName, Object message) {
ResultMessage result = new ResultMessage();
result.setSystem(isSystemMessage);
result.setMessage(message);
if(fromName != null) {
result.setFromName(fromName);
}
return JSON.toJSONString(result);
}
}
3.4 然后就是所有实体类的创建。
对于前端实体类,需要用户,封装http请求实体。
对于聊天室,需要用户发送的信息,服务器给用户发送的信息。
@Data
public class Result {
private boolean flag;
private String message;
}
@Data
public class User {
private String userId;
private String username;
private String password;
}
@Data
public class Message {
private String toName;
private String message;
}
@Data
public class ResultMessage {
private boolean isSystem;
private String fromName;
private Object message;//如果是系统消息是数组
}
3.5 后端基础功能的实现
后端实现登陆功能:用户名可以随意输入,但是密码必须是123。
@PostMapping("/login")
public Result login(@RequestBody User user, HttpSession session) {
Result result = new Result();
if(user != null && "123".equals(user.getPassword())) {
result.setFlag(true);
//将数据存储到session对象中
session.setAttribute("user",user.getUsername());
} else {
result.setFlag(false);
result.setMessage("登陆失败");
}
return result;
}
后端实现获取用户名称功能:
@GetMapping("/getUsername")
public String getUsername(HttpSession session) {
String username = (String) session.getAttribute("user");
return username;
}
3.6 通过session发送消息的核心功能(重点)
@ServerEndpoint(value = "/chat",configurator = GetHttpSessionConfig.class)
@Component
public class ChatEndpoint {
private static Map onlineUsers = new ConcurrentHashMap<>();
static {
// 初始化onlineUsers对象
onlineUsers = new ConcurrentHashMap<>();
}
private HttpSession httpSession;
/**
* 建立websocket连接后,被调用
* @param session
*/
@OnOpen
public void onOpen(Session session, EndpointConfig config) {
//1,将session进行保存
this.httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
String user = (String) this.httpSession.getAttribute("user");
onlineUsers.put(user,session);
//2,广播消息。需要将登陆的所有的用户推送给所有的用户
String message = MessageUtils.getMessage(true,null,getFriends());
broadcastAllUsers(message);
}
public Set getFriends() {
Set set = onlineUsers.keySet();
return set;
}
private void broadcastAllUsers(String message) {
try {
//遍历map集合
Set> entries = onlineUsers.entrySet();
for (Map.Entry entry : entries) {
//获取到所有用户对应的session对象
Session session = entry.getValue();
//发送消息
session.getBasicRemote().sendText(message);
}
} catch (Exception e) {
//记录日志
}
}
/**
* 浏览器发送消息到服务端,该方法被调用
*
* 张三 --> 李四
* @param message
*/
@OnMessage
public void onMessage(String message) {
try {
//将消息推送给指定的用户
Message msg = JSON.parseObject(message, Message.class);
//获取 消息接收方的用户名
String toName = msg.getToName();
String mess = msg.getMessage();
//获取消息接收方用户对象的session对象
Session session = onlineUsers.get(toName);
String user = (String) this.httpSession.getAttribute("user");
String msg1 = MessageUtils.getMessage(false, user, mess);
session.getBasicRemote().sendText(msg1);
} catch (Exception e) {
//记录日志
}
}
/**
* 断开 websocket 连接时被调用
* @param session
*/
@OnClose
public void onClose(Session session) {
//1,从onlineUsers中剔除当前用户的session对象
String user = (String) this.httpSession.getAttribute("user");
onlineUsers.remove(user);
//2,通知其他所有的用户,当前用户下线了
String message = MessageUtils.getMessage(true,null,getFriends());
broadcastAllUsers(message);
}
}
代码重点在于对session的使用,将内容放在对应用户session的共享域中,后端则负责统一管理所有用户的session。
4.1 登陆功能:
4.2 在线与不在线,当后端运行后才能显示在线
4.3 当有其他人登陆时候弹出对应用户名称
4.4 通过点击对应的名称进行一对一聊天
4.5 实现聊天功能