目录
一、websocket是什么
二、实现websocket
2.1参考学习b站资料(一定要看,前后端详细)
2.2学习配套代码
一、websocket是什么
WebSocket_ohana!的博客-CSDN博客
二、实现websocket
2.1参考学习b站资料(一定要看,前后端详细)
01-websocket协议及实现_哔哩哔哩_bilibili
2.2学习配套代码
1.导入pom依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
2.编写配置类
//配置类
@Configuration
public class WebSocketConfig {
@Bean
//注入ServerEndpointExporter bean对象,自动注册使用注解@ServerEndpoint的bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
3.所需要的pojo类:
4.需要的工具类,用于转化信息格式
import com.example.ex1.mes_websocket.pojo.ResultMessage;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class MessageUtils {
public static String getMessage(boolean isSystemMessage,String fromName,Object message){
try {
ResultMessage result = new ResultMessage();
result.setSystem(isSystemMessage);
result.setMessage(message);
if (fromName!=null){
result.setFromName(fromName);
}
//把字符串转成json格式的字符串
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(result);
}catch (JsonProcessingException e){
e.printStackTrace();
}
return null;
}
}
5.登录的验证以及获取用户名的controller
import com.example.ex1.mes_websocket.pojo.Result;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpSession;
@RestController
public class LoginController {
@RequestMapping("/toLogin")
public Result tologin(@RequestParam("user") String user,@RequestParam("pwd") String pwd, HttpSession session){
Result result = new Result();
if (user.equals("张三")&&pwd.equals("123")){
result.setFlag(true);
session.setAttribute("user",user);
}else if (user.equals("李四")&&pwd.equals("123")){
result.setFlag(true);
session.setAttribute("user",user);
}else if (user.equals("123")&&pwd.equals("123")){
result.setFlag(true);
session.setAttribute("user",user);
}
else if (user.equals("王五")&&pwd.equals("123")){
result.setFlag(true);
session.setAttribute("user",user);
}else {
result.setFlag(false);
result.setMessage("登录失败");
}
return result;
}
@RequestMapping("/getUsername")
public String getUsername(HttpSession session){
String username = (String) session.getAttribute("user");
return username;
}
}
6.登录页面(前端页面用到jquery)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="js/jquery.min.js"></script>
<form id="loginForm">
<label>账号:</label>
<input type="text" name="user">
<label>密码:</label>
<input type="password" name="pwd">
<button type="button" id="btn">登录</button>
</form>
<p id="err_msg"></p>
<script>
$("#btn").click(function () {
$.get("toLogin?",$("#loginForm").serialize(),function(res){
if (res.flag){
console.log(res);
location.href = "main.html";
} else {
console.log(res);
$("#err_msg").html(res.message);
}
},"json");
})
</script>
</body>
</html>
7.主页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<style>
#left{
float: left;
width: 30%;
height: 500px;
margin-left: 200px;
}
#right{
float: right;
width: 30%;
height: 500px;
}
#top{
margin-top: 50px;
float: top;
width: 30%;
height: 250px;
}
#content{
border: aquamarine 1px solid;
width: 100%;
height: 300px;
}
#input{
margin-top: 20px;
width: 100%;
height: 200px;
}
#input input{
width: 100%;
height: 100px;
}
#input button{
float: right;
}
#mes_left{
float: left;
}
#mes_right{
float: right;
width: 50%;
text-align: right;
}
</style>
<body>
<script src="js/jquery.min.js"></script>
<h3 style="text-align: center" id="username"></h3>
<div>
<div id="left">
<h4 id="new"></h4>
<div id="content">
</div>
<div id="input">
<input type="text" id="input_text">
<button id="submit">发送</button>
</div>
</div>
<div id="right">
<div id="top">
<p>在线的好友</p>
<div id="hylist">
</div>
</div>
<div id="bottom">
<p>系统广播</p>
<div id="xtlist">
</div>
</div>
</div>
</div>
<script>
var username;
$(function () {
var toName;
$.ajax({
url:"getUsername",
success:function (res) {
username = res;
$("#username").html("用户:"+ username +"<span>在线</span>");
// $("#username").html("用户:123<span>在线</span>");
},
async:false //同步请求,只有上面好了才会接着下面
});
var ws = new WebSocket("ws://localhost:8080/chat");
ws.onopen = function (ev) {
$("#username").html("用户:"+ username +"<span>在线</span>");
}
//接受消息
ws.onmessage = function (ev) {
var datastr = ev.data;
var res = JSON.parse(datastr);
//判断是否是系统消息
if(res.system){
//好友列表
//系统广播
var names = res.message;
var userlistStr = "";
var broadcastListStr = "";
for (var name of names){
if (name != username){
userlistStr += "<a οnclick='showChat(\""+name+"\")'>"+ name +"</a></br>";
broadcastListStr += "<p>"+ name +"上线了</p>";
}
};
$("#hylist").html(userlistStr);
$("#xtlist").html(broadcastListStr);
}else {
//不是系统消息
var str = "<span id='mes_left'>"+ res.message +"</span></br>";
if (toName == res.fromName)
$("#content").append(str);
var chatdata = sessionStorage.getItem(res.fromName);
if (chatdata != null){
str = chatdata + str;
}
sessionStorage.setItem(res.fromName,str);
};
},
ws.onclose = function (ev) {
$("#username").html("用户:"+ username +"<span>离线</span>");
}
showChat = function(name){
// alert("dsaad");
toName = name;
//清空聊天区
$("#content").html("");
$("#new").html("当前正与"+toName+"聊天");
var chatdata = sessionStorage.getItem(toName);
if (chatdata != null){
$("#content").html(chatdata);
}
};
//发送消息
$("#submit").click(function () {
//获取输入的内容
var data = $("#input_text").val();
$("#input_text").val("");
var json = {"toName": toName ,"message": data};
//将数据展示在聊天区
var str = "<span id='mes_right'>"+ data +"</span></br>";
$("#content").append(str);
var chatdata = sessionStorage.getItem(toName);
if (chatdata != null){
str = chatdata + str;
}
sessionStorage.setItem(toName,str);
//发送数据
ws.send(JSON.stringify(json));
})
})
</script>
</body>
</html>
8.获取HttpSession对象的类
import javax.servlet.http.HttpSession;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;
public class GetHttpSessionConfigurator extends ServerEndpointConfig.Configurator {
@Override
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
//获取HttpSession对象
HttpSession httpSession = (HttpSession) request.getHttpSession();
sec.getUserProperties().put(HttpSession.class.getName(),httpSession);
}
}
9.最后的通信类
import com.example.ex1.mes_websocket.pojo.Message;
import com.example.ex1.mes_websocket.utils.MessageUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpSession;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@ServerEndpoint(value = "/chat",configurator = GetHttpSessionConfigurator.class)
@Component
public class ChatEndpoint {
//用来存储每个用户客户端对象的ChatEndpoint对象
private static Map<String,ChatEndpoint> onlineUsers = new ConcurrentHashMap<>();
//声明session对象,通过对象可以发送消息给指定的用户
private Session session;
//声明HttpSession对象,我们之前在HttpSession对象中存储了用户名
private HttpSession httpSession;
//连接建立
@OnOpen
public void onOpen(Session session, EndpointConfig config){
this.session = session;
HttpSession httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
this.httpSession = httpSession;
//存储登陆的对象
String username = (String)httpSession.getAttribute("user");
onlineUsers.put(username,this);
//将当前在线用户的用户名推送给所有的客户端
//1 获取消息
String message = MessageUtils.getMessage(true, null, getNames());
//2 调用方法进行系统消息的推送
broadcastAllUsers(message);
}
private void broadcastAllUsers(String message){
try {
//将消息推送给所有的客户端
Set<String> names = onlineUsers.keySet();
for (String name : names) {
ChatEndpoint chatEndpoint = onlineUsers.get(name);
chatEndpoint.session.getBasicRemote().sendText(message);
}
}catch (Exception e){
e.printStackTrace();
}
}
//返回在线用户名
private Set<String> getNames(){
return onlineUsers.keySet();
}
//收到消息
@OnMessage
public void onMessage(String message,Session session){
//将数据转换成对象
try {
ObjectMapper mapper =new ObjectMapper();
Message mess = mapper.readValue(message, Message.class);
String toName = mess.getToName();
String data = mess.getMessage();
String username = (String) httpSession.getAttribute("user");
String resultMessage = MessageUtils.getMessage(false, username, data);
//发送数据
onlineUsers.get(toName).session.getBasicRemote().sendText(resultMessage);
} catch (Exception e) {
e.printStackTrace();
}
}
//关闭
@OnClose
public void onClose(Session session) {
String username = (String) httpSession.getAttribute("user");
//从容器中删除指定的用户
onlineUsers.remove(username);
MessageUtils.getMessage(true,null,getNames());
}}