流程:
1、在pom引入webSocket所需包
2、后台编写websocket代码
3、微信小程序与后台进行交互代码
1、pom文件
<!-- 使用socket -->
org.java-websocket</groupId>
Java-WebSocket</artifactId>
1.3.0</version>
</dependency>
2.1、单独创建一个socket文件夹用与实现长链接的文件方便以后复制粘贴
再创建MyWebScoket.java
import com.alibaba.fastjson.JSONObject;
import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.Map;
@Component
public class MyWebScoket extends WebSocketServer {
@Autowired
private WsPool wsPool;
private static ApplicationContext applicationContext;
public MyWebScoket() throws UnknownHostException {
}
public MyWebScoket(int port) {
super(new InetSocketAddress(port));
}
public MyWebScoket(InetSocketAddress address) {
super(address);
}
public static void setApplicationContext(ApplicationContext applicationContext){
MyWebScoket.applicationContext = applicationContext;
}
@Override
public void onOpen(WebSocket conn, ClientHandshake handshake) {
// ws连接的时候触发的代码,onOpen中我们不做任何操作
}
@Override
public void onClose(WebSocket conn, int code, String reason, boolean remote) {
System.out.println("用户断开链接:");
//断开连接时候触发代码
userLeave(conn);
System.out.println(reason);
System.out.println("conn:"+conn);
System.out.println("code:"+code);
System.out.println("reason:"+reason);
System.out.println("remote:"+remote);
}
@Override
public void onMessage(WebSocket conn, String message) {
//有用户连接进来
Map<String, String> obj = (Map<String,String>) JSONObject.parse(message);
System.out.println(message);
String username = obj.get("name");
userJoin(conn, username);
}
@Override
public void onError(WebSocket conn, Exception ex) {
//错误时候触发的代码
System.out.println("on error");
ex.printStackTrace();
}
/**
* 去除掉失效的websocket链接
*/
private void userLeave(WebSocket conn){
WsPool.removeUser(conn);
}
/**
* 将websocket加入用户池
* @param conn
* @param userName
*/
private void userJoin(WebSocket conn,String userName){
//这里最为关键 使用spring的注入是行不通的只能走最原始的办法
WsPool wsPool =(WsPool) applicationContext.getBean("wsPool");
wsPool.addUser(userName, conn);
}
这里面的 setApplicationContext 方法作用特别大 解决了使用spring注入为null的问题
如果你使用的是SSM可以参考我的另一篇文章 SSM使用WebSocket进行依赖注入为null的解决办法
2.2 创建一个WsPool 基本上就是方便我们结合业务代码使用创建的
import org.java_websocket.WebSocket;
import org.springframework.stereotype.Component;
import java.util.*;
@Component
public class WsPool {
private static final Map<WebSocket, String> wsUserMap = new HashMap<WebSocket, String>();
/**
* 通过websocket连接获取其对应的用户
*/
public static String getUserByWs(WebSocket conn) {
return wsUserMap.get(conn);
}
/**
* 根据userName获取WebSocket,这是一个list,此处取第一个
* 因为有可能多个websocket对应一个userName(但一般是只有一个,因为在close方法中,我们将失效的websocket连接去除了)
*/
public WebSocket getWsByUser(String userName) {
Set<WebSocket> keySet = wsUserMap.keySet();
synchronized (keySet) {
for (WebSocket conn : keySet) {
String cuser = wsUserMap.get(conn);
if (cuser.equals(userName)) {
return conn;
}
}
}
return null;
}
/**
* 向连接池中添加连接
*/
public void addUser(String userName, WebSocket conn) {
wsUserMap.put(conn, userName); // 添加连接
}
/**
* 获取所有连接池中的用户,因为set是不允许重复的,所以可以得到无重复的user数组
*/
public static Collection<String> getOnlineUser() {
List<String> setUsers = new ArrayList<String>();
Collection<String> setUser = wsUserMap.values();
for (String u : setUser) {
setUsers.add(u);
}
return setUsers;
}
/**
* 移除连接池中的连接
*/
public static boolean removeUser(WebSocket conn) {
if (wsUserMap.containsKey(conn)) {
wsUserMap.remove(conn); // 移除连接
return true;
} else {
return false;
}
}
/**
* 向特定的用户发送数据
*/
public void sendMessageToUser(WebSocket conn, String message) {
String s = wsUserMap.get(conn);
if (null != conn && null != s) {
conn.send(message);
}
}
/**
* 向所有的用户发送消息
*/
public static void sendMessageToAll(String message) {
Set<WebSocket> keySet = wsUserMap.keySet();
synchronized (keySet) {
for (WebSocket conn : keySet) {
String user = wsUserMap.get(conn);
if (user != null) {
conn.send(message);
}
}
}
}
}
这里的WsPool类可以根据客户端请求的唯一标识进行存储和获取 以及对用户发送消息使用
2.3 最后一部我们的后端就完成了 就是设置启动服务的时候启动websocket和占用端口了
我们这里就不使用注解放在启动类里了 感兴趣的可以创建一个类把启动所需的东西放进去然后进行注解配置到springboot的启动类上面就行了
这里我就直接放到启动类里启动了
import com.hnlw.project.merchant.socket.config.MyWebScoket;
import org.java_websocket.WebSocketImpl;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
/**
* 启动程序
*
* @author hnlw
*/
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class HNLWApplication
{
public static void main(String[] args)
{
ConfigurableApplicationContext run = SpringApplication.run(HNLWApplication.class, args);
System.out.println("(♥◠‿◠)ノ゙ SpringBoot项目启动成功 ლ(´ڡ`ლ)゙ ");
//这里特别关键的一步就是对前面2.1创建的MyWebScoket里面编写的setApplicationContext方法进行赋值,项目启动后就赋过去 后面可以直接拿到了
MyWebScoket.setApplicationContext(run);
WebSocketImpl.DEBUG = false;
MyWebScoket s;
s = new MyWebScoket(8888);//WebSocket 的占用端口可以更改为自己习惯的端口
s.start();
System.out.println("(♥◠‿◠)ノ゙ WebSocket启动成功 ლ(´ڡ`ლ)゙ ");
}
}
到此为止后端的就已经完成了,我们看一下微信小程序如何与后台进行交接
二、微信端比较简单
流程:进入页面或进入小程序就建立链接 我这里是结合项目需求进入某个页面时建立链接 也可以进入小程序时就建立链接需要再app.js里面配置一下就行 可以参考进入小程序创建链接 也可根据我下面的 加入到app.js就行
我这里在进入index.wxml 时就创建链接
在页面的js加入 这里的 openSocket 在进入页面触发一下就能建立链接了
这里使用 的 this.data.socketStatus 只是在data中定义了一个属性
openSocket() {
//打开时的动作
wx.onSocketOpen(() => {
console.log('WebSocket 已连接')
this.data.socketStatus = 'connected';
this.sendMessage();
})
//断开时的动作
wx.onSocketClose(() => {
console.log('WebSocket 已断开')
this.data.socketStatus = 'closed'
})
//报错时的动作
wx.onSocketError(error => {
console.error('socket error:', error)
})
// 监听服务器推送的消息
wx.onSocketMessage(message => {
console.log("message",message);
//把JSONStr转为JSON
message = message.data.replace(" ", "");
if (typeof message != 'object') {
message = message.replace(/\ufeff/g, ""); //重点
var jj = JSON.parse(message);
message = jj;
}
console.log("【websocket监听到消息】内容如下:");
console.log(message);
})
// 打开信道
wx.connectSocket({
url: "ws://" + "192.168.0.105" + ":8888",
})
},
//关闭信道
closeSocket() {
if (this.data.socketStatus === 'connected') {
wx.closeSocket({
success: () => {
this.data.socketStatus = 'closed'
}
})
}
},
//发送消息函数
sendMessage() {
if (this.data.socketStatus === 'connected') {
//自定义的发给后台识别的参数 ,我这里发送的是name
wx.sendSocketMessage({
//data: "{\"name\":\"" + wx.getStorageSync('openid') + "\"}"
data: "{\"name\":\"000001\"}"
})
}
},
三、演示流程
3、模拟后台向客户端发送信息
这里模拟我就在后台写了一个接口去向客户端发送请求代码很简单
一个post请求向客户端发送
这里使用的000001是小程序端建立链接时发送过去的唯一标识 推荐使用openId 我这里只是demo实例
4、客户端收到
到此为止就完成了
java后端使用到的类和pom 微信端的小程序代码 也都上传到网盘了 可以下载了看一下
链接: https://pan.baidu.com/s/1dLGB8Jto8dVcjGD9Ar50nA 提取码: 6qr5
如果有哪里描述不清楚可以留言 看到后会 即使更改为更容易理解的方式给更多人!