使用SpringBoot + WebSocket实现单人聊天
作者:互联网
## 前言
>最近在做一个聊天功能,具体需求:类似微信,在一个好友列表中,点击某个好友就可以建立与该好友的聊天连接,向该好友发送消息,对方能够实时显示出来,进行真正意义上的聊天。
在做之前,不管在界面布局,还是功能实现方面都下了一点功夫,最终还是一点点实现了,现在就记录一下。
在编码之前得先了解一下`WebSocket`
> 1. 什么是`WebSocket`?
>
> * `WebSocket`,即Web浏览器与Web服务器之间全双工通信标准;是HTML5中的协议,支持持久连续,http协议不支持持久性连接。Http1.0和HTTP1.1都不支持持久性的链接,HTTP1.1中的keep-alive,将多个http请求合并为1个
> * 一旦确立`WebSocket`通信连接,不论服务器还是客户端,任意一方都可直接向对方发送报文
>
> 2. `WebSocket`特点?
>
> * 推送功能:支持由服务器向客户端推送数据的推送功能,这样,服务器可直接发送数据,而不必等待客户端的请求
> * 减少通信量:只要建立起`WebSocket`,就可以一直保持连接状态
>
>
> 头部字段多了下面2个属性:
>
> ```http
> Upgrade:webSocket
> Connection:Upgrade
> ```
![](https://www.icode9.com/i/ll/?i=img_convert/6cbfa5cb7d9b8ff57af3a42254f6f2ca.png)
## 1、实现效果
![](https://www.icode9.com/i/ll/?i=img_convert/c208de0df2d7bf27f7a958bafe437e19.png)
点击左侧好友列表时,会建立websocket连接,把当前发消息的用户发送给websocket服务器
![](https://www.icode9.com/i/ll/?i=img_convert/6d52813766d6e2473d860ee76c8c9fc4.png)
输入消息
![](https://www.icode9.com/i/ll/?i=img_convert/77b7e01e51d28f605f60df299a6a0b05.png)
![](https://www.icode9.com/i/ll/?i=img_convert/2a6bb7c99100d7e501a8b5448f8ca702.png)
![](https://www.icode9.com/i/ll/?i=img_convert/b4ac4768b14b6df1ffb7f6e88aec762d.png)
## 2、前端实现
```js
聊天消息管理
发送
```
```js
org.springframework.boot
spring-boot-starter-websocket
```
```java
// WebSocketController.java
@Controller
@ServerEndpoint(value = "/websocket/{user}")
@Api(tags = "业务模块-websocket连接接口")
public class WebSocketController {
// 这里使用静态,让 service 属于类
private static ChatMsgService chatMsgService;
// 注入的时候,给类的 service 注入
@Resource
public void setChatService(ChatMsgService chatService) {
WebSocketController.chatMsgService = chatService;
}
// 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
private static int onlineCount = 0;
// concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
private static ConcurrentHashMap<String, WebSocketController> webSocketSet = new ConcurrentHashMap<String, WebSocketController>();
// 与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session WebSocketSession;
// 记录当前发消息的用户
private String user = "";
/**
* 连接建立成功调用的方法
*
* session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
*/
@OnOpen
public void onOpen(@PathParam(value = "user") String param, Session WebSocketsession) {
user = param;
// System.out.println(user);
this.WebSocketSession = WebSocketsession;
webSocketSet.put(param, this);// 加入map中
addOnlineCount(); // 在线数加1
// System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
if (!user.equals("")) {
webSocketSet.remove(user); // 从set中删除
subOnlineCount(); // 在线数减1
// System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
}
}
/**
* 收到客户端消息后调用的方法
*
* @param chatmsg 客户端发送过来的消息
* @param session 可选的参数
*/
@OnMessage
public void onMessage(String chatmsg, Session session) throws SystemException{
JSONObject jsonObject = JSONObject.parseObject(chatmsg);
//给指定的人发消息
sendToUser(jsonObject.toJavaObject(ChatMsgVO.class));
//sendAll(message);
}
/**
* 给指定的人发送消息
*
* @param chatMsg 消息对象
*/
public void sendToUser(ChatMsgVO chatMsg) throws SystemException{
String fromUser = chatMsg.getMFromUser();
String mMsg = chatMsg.getMMsg();
System.out.println(fromUser);
mMsg= EmojiFilter.filterEmoji(mMsg);//过滤输入法输入的表情
chatMsgService.InsertChatMsg(chatMsg);
try {
if (webSocketSet.get(fromUser) != null) {
webSocketSet.get(fromUser).sendMessage(chatMsg.getMFromUser()+"|"+mMsg);
}else{
webSocketSet.get(chatMsg.getMFromUser()).sendMessage("0"+"|"+"当前用户不在线");
}
} catch (IOException e) {
throw new SystemException(SystemCodeEnum.PARAMETER_ERROR,e.getMessage());
}
}
/**
* 给所有人发消息
*
* @param message
*/
private void sendAll(String message) {
String sendMessage = message.split("[|]")[1];
//遍历HashMap
for (String key : webSocketSet.keySet()) {
try {
//判断接收用户是否是当前发消息的用户
if (!user.equals(key)) {
webSocketSet.get(key).sendMessage(sendMessage);
System.out.println("key = " + key);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 发生错误时调用
*
* @param session
* @param error
*/
@OnError
public void one rror(Session session, Throwable error) {
error.printStackTrace();
}
/**
* 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。
*
* @param message
* @throws IOException
*/
public void sendMessage(String message) throws IOException {
this.WebSocketSession.getBasicRemote().sendText(message);
//this.session.getAsyncRemote().sendText(message);
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
WebSocketController.onlineCount++;
}
public static synchronized void subOnlineCount() {
WebSocketController.onlineCount--;
}
}
```
```java
//ChatController.java
@RestController
@RequestMapping("business/chat")
public class ChatMsgController {
@Resource
private ApiUserService apiUserService;
@Resource
private ChatMsgService chatMsgService;
@Resource
private ChatFriendsService chatFriendsService;
@ApiOperation(value = "获取好友聊天记录", notes = "根据当前用户查询好友聊天记录")
@GetMapping("/getFriendMsg/{username}")
public ResponseBean<List> getFriendMsg(@PathVariable String username) throws SystemException {
UserInfoVO userInfoVO = apiUserService.info();
List chatMsgs = chatMsgService.getFriendMsg(userInfoVO.getUsername(), username);
return ResponseBean.success(chatMsgs);
}
@ApiOperation(value = "获取用户好友", notes = "根据用户id查询用户好友")
@GetMapping("/getfriends/{id}")
public ResponseBean<List> getFriends(@PathVariable Long id) throws SystemException {
List chatFriendsList = chatFriendsService.getFriends(id);
return ResponseBean.success(chatFriendsList);
}
}
```
{{this.username}}
-
{{friend.ffriendName}}
-
{{item.mcreateTime | time}}
{{item.mfromUser}} {{item.mmsg}}
标签:WebSocket,SpringBoot,img,单人,void,param,String,public,客户端 来源: https://blog.51cto.com/u_15192324/2900483