技术选型
后端:SpringBoot+MyBatisplus+WebSocket
数据库:Mysql
前端:原生微信小程序
实现思路
系统需要对数据库中的订单进行实时查询,更新状态。因此使用WebSocket保证前后端数据一致性,再通过SpringBoot的定时任务轮询数据库,实现后端与数据库的数据一致性。
实现步骤
1、导入websocket依赖,直接复制到pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2、编写WebSocket配置类,直接复制
@Configuration
public class WebSocketConfig {
/**
* 注入ServerEndpointExporter,
* 这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
3、编写SessionPool工具类实现消息发送,这个可以根据需求自己改写
public class SessionPool {
//key-value : userId - 会话(系统创建)
public static Map<String, Session> sessions = new ConcurrentHashMap<>();//避免多线程问题
public static void close(String sessionId) {
//sessionId是在session中添加了一个标识,准确定位某条session
for (String userId : sessions.keySet()) {
Session session = sessions.get(userId);
if (session.getId().equals(sessionId)) {
sessions.remove(userId);
break;
}
}
}
public static void sendMessage(String userId, String message) {
sessions.get(userId).getAsyncRemote().sendText(message);
}
//消息的群发,业务逻辑的群发
public static void sendMessage(String message) {
for (String sessionId : sessions.keySet()) {
sessions.get(sessionId).getAsyncRemote().sendText(message);
}
}
//点对点的消息推送
public static void sendMessage(Map<String, Object> params) {
String userId = params.get("formUserId").toString();
String toUserId = params.get("toUserId").toString();
String msg = params.get("message").toString();
//获取用户session
Session session = sessions.get(toUserId);
//session不为空的情况下进行点对点推送
if (session != null) {
session.getAsyncRemote().sendText(msg);
}
}
}
4、编写Controller类
先加上注解
@ServerEndpoint("/websocket/{userId}")
@EnableScheduling //开启定时任务
@RestController
@RequestMapping("/api/xxx")
public class xxController{
由该注解可得请求路径为:“ws://localhost:8080/websocket/用户id”
编写业务,里面用到了hutool
//连接建立成功调用的方法,如果需要ws建立时推送消息可写
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId) {
//把session加入连接池
SessionPool.sessions.put(userId, session);
//调用service层查询实时数据
YourData newData=xxService.xx();
//将数据转换为json发送到前端
String json= JSONUtil.toJsonStr(newData);
SessionPool.sendMessage(json);
log.info("Json:{}",json);
log.info("建立连接成功,id:"+userId);
}
//关闭会话的时候调用,如果需要ws断连时推送消息可写
@OnClose
public void onClose(Session session) throws IOException {
SessionPool.close(session.getId());
log.info("断开连接成功,id:"+session.getId());
session.close();
}
//接收到客户端的消息后调用
@OnMessage
public void onMessage(String message, Session session) {
//接收客户端数据,更新数据库
xxxxxxxxx;
}
接下来在Controller中定时调用Service的方法获取数据库中的数据,通过ws推送到前端
@Scheduled(fixedDelay = 1000) 定时任务,一秒执行一次
// 定时任务,每秒查询一次数据库,将数据通过ws推送到前端
@Scheduled(fixedDelay = 1000)
public void pollDatabaseForNewData() {
//调用service层查询实时数据
YourData newData=xxService.xx();
//将数据转换为json发送到前端
String json= JSONUtil.toJsonStr(newData);
SessionPool.sendMessage(json);
}
5、前端建立websocket连接,以小程序为例
js代码:
openSocket() {
try {
console.log("建立websocket连接...")
// 连接后台服务器
// 用户id
var id="xxxxxxxxxxxxx";
this.SocketTask = wx.connectSocket({
url: `ws://127.0.0.1:8080//websocket/${id}`,
success: (res) => {
console.log("连接成功!,res:", res)
}
})
} catch (e) {
console.log(e)
}
//连接成功后的操作
this.SocketTask.onOpen(() => {
console.log('WebSocket 已连接')
})
//断开后台服务器的操作
this.SocketTask.onClose(() => {
console.log('WebSocket 已断开')
// this.ReConnect()
})
//报错时执行
this.SocketTask.onError(error => {
// this.ReConnect()
})
// 监听服务器推送的消息
this.SocketTask.onMessage(message => {
// 将json数据转换为对象
var obj = JSON.parse(message.data)
//数据处理业务
xxxxxx;
})
},
// 关闭websocket服务
closeSocket() {
this.SocketTask.close({
success: () => {
console.log("断开连接");
}
})
},
前端也可以使用vue等等,需要自己去找websocket相关接口,后端是通用的。