
在网站项目开发中,我们经常会有在线客服的功能,通过网站开启一个聊天室,进行客服解答功能,本节我们使用websocket实现一个简单的网站在线客服聊天功能,效果如下:
正文org.springframework.boot spring-boot-starter-websocket
package com.yundi.atp.platform.websocket;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
package com.yundi.atp.platform.websocket;
import com.alibaba.fastjson.JSON;
import com.yundi.atp.platform.module.test.entity.ChatMsg;
import com.yundi.atp.platform.module.test.service.ChatMsgService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
@Slf4j
@Component
@ServerEndpoint("/websocket/chat/{userName}")
public class WebSocketServer {
private Session session;
private static CopyOnWriteArraySet webSockets = new CopyOnWriteArraySet<>();
private static Map sessionPool = new ConcurrentHashMap<>();
private static ChatMsgService chatMsgService;
private static String SUPER_ADMIN = "super_admin";
@Autowired
public void setWebSocketServer(ChatMsgService chatMsgService) {
WebSocketServer.chatMsgService = chatMsgService;
}
@onOpen
public void onOpen(Session session, @PathParam(value = "userName") String userName) {
List onlineList = new ArrayList<>();
this.session = session;
webSockets.add(this);
sessionPool.put(userName, session);
log.info("【websocket消息】有新的连接,总数为:" + webSockets.size());
Iterator> iterator = sessionPool.entrySet().iterator();
while (iterator.hasNext()) {
onlineList.add(iterator.next().getKey());
}
onlineList.remove(SUPER_ADMIN);
Map map = new HashMap<>(16);
map.put("key", 1);
map.put("onlineList", onlineList);
map.put("userList", chatMsgService.getUserList());
this.sendoneMessage(SUPER_ADMIN, JSON.toJSonString(map));
}
@onClose
public void onClose(@PathParam(value = "userName") String userName) {
webSockets.remove(this);
sessionPool.remove(userName);
log.info("【websocket消息】连接断开,总数为:" + webSockets.size());
List onlineList = new ArrayList<>();
Iterator> iterator = sessionPool.entrySet().iterator();
while (iterator.hasNext()) {
onlineList.add(iterator.next().getKey());
}
onlineList.remove(SUPER_ADMIN);
Map map = new HashMap<>(16);
map.put("key", 2);
map.put("onlineList", onlineList);
map.put("userList", chatMsgService.getUserList());
this.sendoneMessage(SUPER_ADMIN, JSON.toJSonString(map));
}
@onMessage
public void onMessage(String message) {
ChatMsg chatMsg = JSON.parseObject(message, ChatMsg.class);
chatMsgService.save(chatMsg);
Map map = new HashMap<>(16);
map.put("key", 3);
map.put("data", chatMsg);
this.sendoneMessage(chatMsg.getSender(), JSON.toJSonString(map));
this.sendoneMessage(chatMsg.getReceiver(), JSON.toJSonString(map));
}
public void sendAllMessage(String message) {
for (WebSocketServer webSocket : webSockets) {
log.info("【websocket消息】广播消息:" + message);
try {
webSocket.session.getAsyncRemote().sendText(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void sendoneMessage(String userName, String message) {
log.info("【websocket消息】单点消息:" + message);
Session session = sessionPool.get(userName);
if (session != null) {
try {
session.getAsyncRemote().sendText(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
package com.yundi.atp.platform.module.test.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yundi.atp.platform.common.Result;
import com.yundi.atp.platform.module.test.entity.ChatMsg;
import com.yundi.atp.platform.module.test.service.ChatMsgService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
@Api(tags = "聊天室接口")
@RestController
@RequestMapping("/test/chatMsg")
public class ChatMsgController {
@Autowired
private ChatMsgService chatMsgService;
@ApiOperation(value = "获取聊天室地址")
@GetMapping(value = "/getWebSocketAddress/{username}")
public Result getWebSocketAddress(HttpServletRequest request, @PathVariable(value = "username") String username) throws UnknownHostException {
String address = "ws://" + InetAddress.getLocalHost().getHostAddress() + ":" + request.getServerPort() + request.getContextPath() + "/websocket/chat/" + username;
return Result.success(address);
}
@ApiOperation(value = "获取历史聊天记录")
@GetMapping(value = "/getHistoryChat/{username}")
public Result getWebSocketAddress(@PathVariable(value = "username") String username) {
List list = chatMsgService.list(new QueryWrapper()
.and(wrapper -> wrapper.eq("sender", username).or().eq("receiver", username))
.orderByDesc("create_time"));
List collect = list.stream().sorted(Comparator.comparing(ChatMsg::getCreateTime)).collect(Collectors.toList());
return Result.success(collect);
}
@ApiOperation(value = "获取用户列表")
@GetMapping(value = "/getUserList")
public Result getUserList() {
List userList = chatMsgService.getUserList();
return Result.success(userList);
}
}
package com.yundi.atp.platform.module.test.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.yundi.atp.platform.module.test.entity.ChatMsg; import com.yundi.atp.platform.module.test.mapper.ChatMsgMapper; import com.yundi.atp.platform.module.test.service.ChatMsgService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class ChatMsgServiceImpl extends ServiceImplimplements ChatMsgService { @Autowired private ChatMsgMapper chatMsgMapper; @Override public List getUserList() { List userList = chatMsgMapper.getUserList(); return userList; } }
package com.yundi.atp.platform.module.test.mapper; import com.baomidou.mybatisplus.core.mapper.baseMapper; import com.yundi.atp.platform.module.test.entity.ChatMsg; import java.util.List; public interface ChatMsgMapper extends baseMapper{ List getUserList(); }
SELECT sender FROM `chat_msg` where sender != 'super_admin' GROUP BY sender
ATP客服
当前在线人数:{{ online }}
{{ username }}
{{ item }}
{{ item }}
{{ item.sender }}
{{ item.createTime | dataFormat('yyyy-MM-dd HH:mm') }}
{{ item.msg }}
{{ item.sender }}
{{ item.createTime | dataFormat('yyyy-MM-dd HH:mm') }}
{{ item.msg }}
客户
客户
{{ item.sender }}
{{ item.createTime | dataFormat('yyyy-MM-dd HH:mm') }}
{{ item.msg }}
{{ item.sender }}
{{ item.createTime | dataFormat('yyyy-MM-dd HH:mm') }}
{{ item.msg }}
发送
发送
.container {
padding-top: 50px;
.box-card {
margin: auto;
width: 800px;
height: 800px;
max-height: 900px;
::v-deep .el-card__header {
background: #867ba9 !important;
border-bottom: none;
padding: 0;
}
::v-deep .el-card__body {
padding: 0px !important;
position: relative;
.content {
height: 600px;
background: #ddd;
overflow-y: auto;
.el-divider--horizontal {
margin: 0;
}
.active {
color: #0080ff;
}
.mark {
background: #deb068;
}
.item {
margin-top: 10px;
margin-right: 10px;
}
}
.operate {
padding: 5px 15px;
}
}
}
}
本节内容到这里就结束了,我们下期见。。。