今天又是元气满满的一天,元气满满那也要分享下自己慢慢弄的即时通讯的东东吧
首先引入pom.xml种jar
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
如果你已经习惯了前后端分离开发,自己想自己写着试试,那么就要引入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
主要核心的也就websocket的jar
首先写好html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>LeIM</title>
</head>
<body>
<h3>LeIM</h3>
<p>【用户id】:
<div><input id="userId" name="用户id" type="text"></div>
<p>【接受信息用户id】:
<div><input id="toUserId" name="接受信息用户id" type="text"></div>
<p>【信息内容】:
<div><input id="contentText" name="内容" type="file"></div>
<p>操作:
<div><a onclick="openSocket()">连接</a></div>
<p>【操作】:
<div><a onclick="sendMessage()">发送</a></div>
<p>【消息】:
<div id="content"></div>
</body>
<script type="text/javascript" src="/structs2_day01_atm/js/jquery-1.11.3.js"></script>
<script>
var socket;
function openSocket() {
if (typeof (WebSocket) == "undefined") {
console.log("您的浏览器不支持WebSocket");
} else {
console.log("您的浏览器支持WebSocket");
//实现化WebSocket对象,指定要连接的服务器地址与端口 建立连接
var userId = document.getElementById('userId').value;
var socketUrl = "ws://127.0.0.1:8080/webSocket/" + userId;
console.log(socketUrl);
if (socket != null) {
socket.close();
socket = null;
}
socket = new WebSocket(socketUrl);
//打开事件
socket.onopen = function () {
console.log("websocket已打开");
//socket.send("这是来自客户端的消息" + location.href + new Date());
};
//获得消息事件
socket.onmessage = function (msg) {
var serverMsg = "收到服务端信息:" + msg.data;
console.log(serverMsg);
//发现消息进入 开始处理前端触发逻辑
var a = document.getElementById("content")
a.innerHTML += "<p>" + msg.data + "<p>" + "<br></<br>";
};
//关闭事件
socket.onclose = function () {
console.log("websocket已关闭");
};
//发生了错误事件
socket.onerror = function () {
console.log("websocket发生了错误");
}
}
}
function sendMessage() {
if (typeof (WebSocket) == "undefined") {
console.log("您的浏览器不支持WebSocket");
} else {
var toUserId = document.getElementById('toUserId').value;
var userId = document.getElementById('userId').value;
var contentText = document.getElementById('contentText').value;
var msg = '{"name":"' + toUserId + '","fName":"' + userId + '","contentText":"' + contentText + '"}';
console.log(msg);
socket.send(msg);
}
}
</script>
</html>
再创建配置类
WebSocketConfig.java
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会自动注册使用@ServerEndpoint注解声明的websocket endpoint
* @return
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
控制器
import com.java.LeIM.Server.WebSocketServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
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.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import java.util.HashMap;
import java.util.Map;
@Controller
public class SocketController {
@Autowired
private WebSocketServer webSocketServer;
@RequestMapping("/index")
public String index() {
return "index";
}
@ResponseBody
@GetMapping("/infoLeIM")
public ModelAndView socket() {
ModelAndView mav=new ModelAndView("/webSocket");
// mav.addObject("userId", userId);
return mav;
}
}
以及websocket服务类
import com.alibaba.fastjson.JSONObject;
import com.java.LeIM.Model.Vo.IM;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
@ServerEndpoint("/webSocket/{sid}")
@Component
public class WebSocketServer {
//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
private static AtomicInteger onlineNum = new AtomicInteger();
//concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketServer对象。
private static ConcurrentHashMap<String, Session> sessionPools = new ConcurrentHashMap<>();
private static ArrayList<IM> arrayList = new ArrayList();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//发送消息
public void sendMessage(Session session, String message) throws IOException {
if (session != null) {
synchronized (session) {
// System.out.println("发送数据:" + message);
session.getBasicRemote().sendText(message);
}
}
}
//给指定用户发送信息
public void sendInfo(String userName, String message) throws IOException {
Session session = sessionPools.get(userName);
try {
sendMessage(session, message);
} catch (Exception e) {
e.printStackTrace();
}
}
//建立连接成功调用
@OnOpen
public void onOpen(Session session, @PathParam(value = "sid") String userName) {
sessionPools.put(userName, session);
addOnlineCount(); //这是单独发送消息 故注释掉
System.out.println(userName + "加入webSocket!当前人数为" + onlineNum);
try {
//sendMessage(session, "欢迎" + userName + "上线!");
sendInfo(userName, "欢迎" + userName + "上线!");
for (int j = 0; j < arrayList.size(); j++) {
if (userName.equals(arrayList.get(j).getReceiveName())) {
//发送未读消息
sendInfo(userName, arrayList.get(j).getContent());
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
//关闭连接时调用
@OnClose
public void onClose(@PathParam(value = "sid") String userName) {
sessionPools.remove(userName);
subOnlineCount();
System.out.println(userName + "断开webSocket连接!当前人数为" + onlineNum);
}
//收到客户端信息
@OnMessage
public void onMessage(String message) throws IOException {
//JSONObject json = JSONObject.fromObject(jsonStr);
message = message.replace("\\", "");
JSONObject json = JSONObject.parseObject(message);
String userName = json.getString("name");
String fName = json.getString("fName");
message = json.getString("contentText");
sendInfo(fName, message);
int i = 1;
if (sessionPools.get(userName) == null) {
for (Session session : sessionPools.values()) {
i = i + 1;
System.out.println("===他未上线=====>" + userName);
//操作未上线存储 (这部分是为了模拟数据可能会丢失,因为不能保证双方都开启了websocket,模拟上线了就会推送消息。IM是个对象存储相关信息的)
IM im = new IM();
im.setId(i);
im.setContent(message);
im.setSendId(1);
im.setSendName(fName);
im.setReceiveId(2);
im.setReceiveName(userName);
im.setSendDate(sdf.format(new Date()));
im.setIsCount(1);
arrayList.add(im);
}
}else{
sendInfo(userName, message);
}
}
//错误时调用
@OnError
public void onError(Session session, Throwable throwable) {
System.out.println("发生错误");
throwable.printStackTrace();
}
public static void addOnlineCount() {
onlineNum.incrementAndGet();
}
public static void subOnlineCount() {
onlineNum.decrementAndGet();
}
}
启动服务:localhost:8080/infoLeIM (8080是我这边默认的端口号,实际情况根据你的配置)
页面出来后,只需填写发送人和接收人的唯一标识了,这里是一对一聊天,改成多对多换个sendMessage()方法即可。
谢谢!