续:spring boot 完整后端接口案例_cc&的博客-csdn博客
后台代码
1.在pom.xml中添加spring-boot-starter-
<!--websocket-->
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-websocket</artifactid>
</dependency>
2. 添加配置,先在src\main\resources\application.yml中添加:
server:
max-http-header-size: 8192
如果不加的话可能导致无法进行访问。
3.新建一个配置类,主要一个bean,用来启动服务是也启动websocket服务
package com.cc.springserver.config;
import org.springframework.context.annotation.bean;
import org.springframework.context.annotation.configuration;
import org.springframework.web.socket.server.standard.serverendpointexporter;
@configuration
public class websocketconfig {
//websocket
@bean
public serverendpointexporter serverendpointexporter() {
return new serverendpointexporter();
}
}
注意:这个类必须有@configuration注解
4.新建一个model来封装进行对话的对象
package com.cc.springserver.entity;
import javax.websocket.session;
public class socketuserinfo {
//用户sessionid
private string sessionid;
//用户session
private session session;
//目标用户sessionid
private string targetsessionid;
//用户角色
private string userrole;
public string getuserrole() {
return userrole;
}
public void setuserrole(string userrole) {
this.userrole = userrole;
}
public string getsessionid() {
return sessionid;
}
public void setsessionid(string sessionid) {
this.sessionid = sessionid;
}
public session getsession() {
return session;
}
public void setsession(session session) {
this.session = session;
}
public string gettargetsessionid() {
return targetsessionid;
}
public void settargetsessionid(string targetsessionid) {
this.targetsessionid = targetsessionid;
}
}
5.新建一个controller类来管理socket会话,它主要完成如下场景业务:
package com.cc.springserver.controller;
import com.alibaba.fastjson.json;
import com.cc.springserver.entity.socketuserinfo;
import org.springframework.stereotype.component;
import javax.websocket.*;
import javax.websocket.server.pathparam;
import javax.websocket.server.serverendpoint;
import java.io.ioexception;
import java.util.hashmap;
import java.util.map;
import java.util.concurrent.concurrenthashmap;
//参数role判断用户角色0是客服,1是用户
@serverendpoint(value = "/websocket/{role}")
@component
public class websocketcontroller {
//用本地线程保存session
private static threadlocal<session> sessions = new threadlocal<session>();
//保存所有连接上的用户的session
private static map<string, socketuserinfo> usersessionmap = new concurrenthashmap<>();
//保存在线客服的session
private static map<string, socketuserinfo> serversessionmap = new concurrenthashmap<>();
//连接
@onopen
public void onopen(session session, @pathparam(value="role") integer role) {
//默认返回错误状态
map<string, string> resultmap = new hashmap<>();
resultmap.put("state", "error");
//保证各个线程里的变量相对独立于其他线程内的变量
sessions.set(session);
//客服上线
if (role.equals(0)) {
//创建一个在线客服信息
socketuserinfo serverinfo = new socketuserinfo();
serverinfo.setsessionid(session.getid());
serverinfo.setsession(session);
serverinfo.setuserrole("客服");
//告诉客服连接成功
resultmap.put("state", "success");
//去查询是否有排队中的用户
//如果存在排队的用户,就将用户和客服绑定
if (findlineuser() != null){
socketuserinfo userinfo = usersessionmap.get(findlineuser());
//将用户绑定到客服
serverinfo.settargetsessionid(userinfo.getsessionid());
//将客服绑定到用户
userinfo.settargetsessionid(serverinfo.getsessionid());
usersessionmap.put(userinfo.getsessionid(), userinfo);
system.out.println("客户"+ serverinfo.getsessionid() + "正在为用户" + userinfo.getsessionid()+"服务");
map<string, string> result = new hashmap<>();
//客服显示用户信息
result.put("msg", "正在为用户"+userinfo.getsessionid()+"服务!");
sendmsg(serverinfo.getsession(), json.tojsonstring(result));
//告诉用户有客服为他服务
result.put("msg", "客服"+serverinfo.getsessionid()+"正在为您服务!");
sendmsg(userinfo.getsession(), json.tojsonstring(result));
}
//将在线客服信息保存到map中
serversessionmap.put(session.getid(), serverinfo);
system.out.println("客服:" + serverinfo.getsessionid() + "连接上服务器,当前在线客服共计:" + serversessionmap.size());
}
if (role.equals(1)) {
//创建一个在线用户信息
socketuserinfo userinfo = new socketuserinfo();
userinfo.setsessionid(session.getid());
userinfo.setsession(session);
userinfo.setuserrole("用户");
//告诉用户连接成功
resultmap.put("state", "success");
//去查询是否有在线的客服
//有空闲客服就将用户和客服绑定
if (findfreeserver() != null){
socketuserinfo serverinfo = serversessionmap.get(findfreeserver());
//将用户绑定到客服
serverinfo.settargetsessionid(userinfo.getsessionid());
serversessionmap.put(serverinfo.getsessionid(), serverinfo);
//将客服绑定到用户
userinfo.settargetsessionid(serverinfo.getsessionid());
system.out.println("客户"+ serverinfo.getsessionid() + "正在为" + userinfo.getsessionid()+"服务");
map<string, string> result = new hashmap<>();
//客服显示用户信息
result.put("msg", "正在为用户"+userinfo.getsessionid()+"服务!");
sendmsg(serverinfo.getsession(), json.tojsonstring(result));
result.put("msg", "客服"+serverinfo.getsessionid()+"正在为您服务!");
sendmsg(userinfo.getsession(), json.tojsonstring(result));
} else {
//告诉用户系统繁忙
resultmap.put("msg", "系统繁忙!");
}
//将在线用户信息保存到map中
usersessionmap.put(session.getid(), userinfo);
system.out.println("用户编号:" + userinfo.getsessionid() + "连接上服务器,当前在线用户共计:" + usersessionmap.size());
}
//返回连接信息
string result = json.tojsonstring(resultmap);
system.out.println(result);
sendmsg(session, result);
}
//关闭连接
@onclose
public void onclose(session session) {
socketuserinfo serverinfo = serversessionmap.get(session.getid());
//客服下线
if (serverinfo != null) {
//将客户从map中移除
serversessionmap.remove(session.getid());
//查看是否有服务服务对象
if (null != serverinfo.gettargetsessionid()){
//给用户说系统错误
map<string, string> result = new hashmap<>();
result.put("msg", "系统错误,请刷新重试!");
sendmsg(usersessionmap.get(serverinfo.gettargetsessionid()).getsession(), json.tojsonstring(result));
}
system.out.println("客服编号:" + serverinfo.getsessionid() + "退出了连接,当前在线客服共计:" + serversessionmap.size());
} else {//用户下线
//将用户从map中移除
usersessionmap.remove(session.getid());
//从客服中解绑
for (socketuserinfo serversocketinfo: serversessionmap.values()) {
//查找绑定的客服,即客服绑定的用户不为空,并且绑定的用户id和现在下线的用户id一样
if (serversocketinfo.gettargetsessionid() != null && serversocketinfo.gettargetsessionid().equals(session.getid())){
//解绑
serversocketinfo.settargetsessionid(null);
serversessionmap.put(serversocketinfo.getsessionid(), serversocketinfo);
system.out.println("用户编号:" + session.getid() + "断开了与客服" + serversocketinfo.getsessionid() + "的连接");
//客服解绑以后,可能还会有在线排队的用户,就让这个客服去
string lineuser = findlineuser();
if (lineuser != null){
//将用户绑定到客服
serversocketinfo.settargetsessionid(lineuser);
serversessionmap.put(serversocketinfo.getsessionid(), serversocketinfo);
//将客服绑定到用户
usersessionmap.get(lineuser).settargetsessionid(serversocketinfo.getsessionid());
system.out.println("客户"+ serversocketinfo.getsessionid() + "正在为" + lineuser+"服务");
map<string, string> result = new hashmap<>();
//客服显示用户信息
result.put("msg", "正在为用户"+lineuser+"服务!");
sendmsg(serversocketinfo.getsession(), json.tojsonstring(result));
//用户显示客户信息
result.put("msg", "客服"+serversocketinfo.getsessionid()+"正在为您服务!");
sendmsg(usersessionmap.get(lineuser).getsession(), json.tojsonstring(result));
}
}
}
system.out.println("用户编号:" + session.getid() + "退出了连接,当前在线用户共计:" + usersessionmap.size());
}
}
//用户和客户端互相传递消息
@onmessage
public void onmessage(string message, session session) {
//消息
map<string, string> result = new hashmap<>();
socketuserinfo serverinfo = serversessionmap.get(session.getid());
//客服消息
if (serverinfo != null) {
system.out.println("客服"+ session.getid()+"发送消息:\""+ message +"\"给用户"+serversessionmap.get(session.getid()).gettargetsessionid());
result.put("msg", "客服"+session.getid()+":"+message);
//将消息发送给用户
//要判断是否绑定到有用户如果有就将消息传递到用户
if (null != serversessionmap.get(session.getid()).gettargetsessionid()){
sendmsg(usersessionmap.get(serversessionmap.get(session.getid()).gettargetsessionid()).getsession(), json.tojsonstring(result));
} else {//如果没有就将消息给自己,嘻嘻嘻
sendmsg(session, json.tojsonstring(result));
}
} else {//用户消息
system.out.println("用户"+ session.getid()+"发送消息:\""+ message +"\"给客户"+usersessionmap.get(session.getid()).gettargetsessionid());
result.put("msg", "用户"+session.getid()+":"+message);
//将消息发送给客服
//判断是否绑定了客服,如果有就发送消息
if (null != usersessionmap.get(session.getid()).gettargetsessionid()){
sendmsg(serversessionmap.get(usersessionmap.get(session.getid()).gettargetsessionid()).getsession(), json.tojsonstring(result));
} else{//同上
sendmsg(session,json.tojsonstring(result));
}
}
}
//异常
@onerror
public void onerror(session session, throwable throwable) {
system.out.println("发生异常!");
throwable.printstacktrace();
}
//统一的发送消息方法
private synchronized void sendmsg(session session, string msg) {
try {
session.getbasicremote().sendtext(msg);
} catch (ioexception e) {
e.printstacktrace();
}
}
//查询排队用户
private synchronized string findlineuser(){
//判断是否有用户
if (usersessionmap.size() > 0){
//遍历所有用户,查找一个排队的用户
for (socketuserinfo userinfo: usersessionmap.values()) {
if (null == userinfo.gettargetsessionid()){
return userinfo.getsessionid();
}
}
}
return null;
}
//查询在线空闲客服
private synchronized string findfreeserver(){
//判断是否有客服
if (serversessionmap.size() > 0){
//遍历所有客服,查找一个空闲的客服
for (socketuserinfo serverinfo: serversessionmap.values()) {
if (null == serverinfo.gettargetsessionid()){
return serverinfo.getsessionid();
}
}
}
return null;
}
}
后台代码到这来就完成了。
前端代码
1) 客户端
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>辕门-在线咨询</title>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
</head>
<body>
<p id="message"></p>
<form id="clientchat">
<input type="text" style="display: none;" id="username" />
<input type="text" style="display: none;" id="targetusername" />
<input type="text" id="sendmsg"></input>
<button type="button" onclick="send()">发送</button>
</form>
</body>
<script>
var websocket = null;
var userid = null;
//判断当前浏览器是否支持websocket
if('websocket' in window){
websocket = new websocket("ws://127.0.0.1:9999/websocket/1");
} else {
alert("don't support websocket!")
}
//连接发生错误的回调方法
websocket.onerror = function(){
alert("connect error!");
};
//连接成功建立的回调方法
websocket.onopen = function(event){
setmessageinnerhtml("连接已建立!");
}
//接收到消息的回调方法
websocket.onmessage = function(event){
var result = event.data
var ob = json.parse(result)
//判断用户状态
if(ob.state != undefined && ob.state != "success"){
setmessageinnerhtml("非法连接!");
websocket.close();
}
//判断是否有消息
if(ob.msg != undefined){
setmessageinnerhtml(ob.msg);
}
}
//连接关闭的回调方法
websocket.onclose = function(){
setmessageinnerhtml("close");
}
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function(){
websocket.close();
}
//将消息显示在网页上
function setmessageinnerhtml(innerhtml){
document.getelementbyid('message').innerhtml += innerhtml + '<br/>';
}
//关闭连接
function closewebsocket(){
websocket.close();
}
//发送消息
function send(){
var sendmsg = $("#sendmsg").val();
setmessageinnerhtml("我 :" + sendmsg)
websocket.send(sendmsg);
$("#sendmsg").val("");
}
</script>
</html>
2)服务端
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>辕门-im</title>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
</head>
<body>
<p id="message"></p>
<form id="clientchat">
<input type="text" style="display: none;" id="username" />
<input type="text" style="display: none;" id="targetusername" />
<input type="text" id="sendmsg"></input>
<button type="button" onclick="send()">发送</button>
</form>
</body>
<script>
var websocket = null;
var userid = null;
//判断当前浏览器是否支持websocket
if('websocket' in window){
websocket = new websocket("ws://127.0.0.1:9999/websocket/0");
} else {
alert("don't support websocket!")
}
//连接发生错误的回调方法
websocket.onerror = function(){
alert("connect error!");
};
//连接成功建立的回调方法
websocket.onopen = function(event){
setmessageinnerhtml("连接已建立!");
}
//接收到消息的回调方法
websocket.onmessage = function(event){
var result = event.data
var ob = json.parse(result)
//判断用户状态
if(ob.state != undefined && ob.state != "success"){
setmessageinnerhtml("非法连接!");
websocket.close();
}
//判断是否有消息
if(ob.msg != undefined){
setmessageinnerhtml(ob.msg);
}
}
//连接关闭的回调方法
websocket.onclose = function(){
setmessageinnerhtml("close");
}
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function(){
websocket.close();
}
//将消息显示在网页上
function setmessageinnerhtml(innerhtml){
document.getelementbyid('message').innerhtml += innerhtml + '<br/>';
}
//关闭连接
function closewebsocket(){
websocket.close();
}
//发送消息
function send(){
var sendmsg = $("#sendmsg").val();
setmessageinnerhtml("我 :" + sendmsg)
websocket.send(sendmsg);
$("#sendmsg").val("");
}
</script>
</html>
发表评论