springboot 与 微信小程序实现 WebSocket通信
文章摘要
由于项目功能需求,要在springboot与微信小程序之间实现WebSocket连接,Google了一天虽然底层还不明白,但至少能跑起来能用不是么。
此文章将记录从新建项目开始的大多数操作,如哪里有错误请诸位看到的大佬指点下,谢谢
spring版本:2.2.0
java版本:1.8
Tomcat版本:9.0.27
maven版本:3.5.4
微信小程序开发工具版本:Stable V1.02.1910120
微信小程序开发工具基础调试库版本:2.9.2
这些一路默认各位大佬已经配置好了,如果没有配置好,emm,不怪我,别找我
tomcat配置SSL后可以直接用wss连接,不需要做额外的配置。也就是https能正常连接,那么wss也可以正常连接
微信小程序WebSocket实现
先写一下微信小程序的吧,因为spring实现WebSocket有三种方式,我会写下其中两种。微信小程序的WebSocket实现就这一种(我只是根据官方文档来的,也许会有多种),要看spring的直接往下滑吧。代码就不过多解释了,请参考官方文档,肯定比我了解的详细多了
wechatdevtools_3tl0dh9EDM.png页面wxml代码
<text>{{response}}</text>
页面js代码
Page({
/**
* 页面的初始数据
*/
data: {
response:""
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
var that = this
// 创建一个 WebSocket 连接
wx.connectSocket({
url: 'ws://127.0.0.1:8088/WebSocketDemo_war/websocketapi',
})
/////////////////////////
// 监听 WebSocket 连接打开事件
wx.onSocketOpen(function (res){
// 通过 WebSocket 连接发送数据
wx.sendSocketMessage({
data: "Hello Spring WebSocket",
success(){
console.log("数据发送成功")
// 监听 WebSocket 接受到服务器的消息事件
wx.onSocketMessage(function(re){
that.setData({ response: re.data})
console.log("SocketMessage: "+re.data)
})
//////////////////////////////////////
},
fail(){
console.log("数据发送失败")
}
})
/////////////////////////////
})
///////////////////////////////
},
})
SpringBoot WebSocket实现
新建springboot项目
新建项目,选Spring Initializr,next 想调的可以随便调,这里我作为演示就不动了,一律默认,next 这里再Spring Web打上勾,next 项目名字可以更改,这里我改了下,Finish接下来就让代码跑一会儿,等创建完成
创建完就是这个样子了,记得把右下角的Enable Auto-Import点了springboot内置了tomcat,所以可以有两种方式启动,一种使用spring内置的Tomcat启动,一种用外置Tomcat启动。使用mvn命令打包后第一种生成Jar包,第二种生成War包。我就两个都写一下吧。
下面是pom.xml文件配置
使用spring内置Tomcat启动,直接在<dependencies>标签内添加以下代码
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
使用外置Tomcat启动需要额外做一些修改,额外添加以下代码
<packaging>war</packaging>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- 移除嵌入式tomcat插件 -->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<!--打包的时候可以不用包进去,别的设施会提供。事实上该依赖理论上可以参与编译,测试,运行等周期。
相当于compile,但是打包阶段做了exclude操作-->
<scope>provided</scope>
</dependency>
下面是我的完整的pom.xml文件配置,因为要打包成war包,也就是使用外置Tomcat启动。所以各位根据自己需要看着改吧。其实都可以添加到pom里。在idea里不影响,两种都能启动。如果需要使用mvn命令打包的话还是改改吧。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<!-- 打包成war包,添加第18行代码-->
<packaging>war</packaging>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- 在这里添加 29-35行代码-->
<!-- 移除嵌入式tomcat插件 -->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 在这里添加 39-45行代码-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<!--打包的时候可以不用包进去,别的设施会提供。事实上该依赖理论上可以参与编译,测试,运行等周期。
相当于compile,但是打包阶段做了exclude操作-->
<scope>provided</scope>
</dependency>
<!-- 添加 48-51行代码-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
在基于Spring的应用中使用WebSocket一般可以有以下三种方式(也许会有多总,我这里只写前两种):
- 使用Java提供的@ServerEndpoint注解实现
- 使用Spring提供的低层级WebSocket API实现
- 使用STOMP消息实现
使用@ServerEndpoint注解实现
在com.example.demo下新建Controller包,在Controller包里新建WebSocketServerEndpoint类,在WebSocketServerEndpoint类添加代码。
类名不一样的注意修改
代码:
@ServerEndpoint("/websocketapi")
public class WebSocketServerEndpoint {
@OnMessage
public void handleMessage(Session session, String message) throws IOException {
System.out.println("服务器接收到的消息:"+message);
session.getBasicRemote().sendText("服务器回复的消息: " + "Hello,Are you OK?");
}
}
使用外置Tomcat启动
添加tomcat,会使用外置的tomcat来运行,注意URL和端口号,我这里改了下添加时右下角会有一个Fix报错,点他选第一个
使用spring内置Tomcat启动
Jar包启动需要额外配置一下,在Controller包里新建WebSocketServerEndpointConfig类,添加代码
@Configuration
@EnableWebSocket
public class WebSocketServerEndpointConfig {
@Bean
public WebSocketServerEndpoint reverseWebSocketEndpoint() {
return new WebSocketServerEndpoint();
}
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
配置完成后,直接点右上角启动DemoApplication。
如果要以外置Tomcat启动,请把WebSocketServerEndpointConfig注释掉,否则会报错
添加完后点击运行就OK了。
然后在微信小程序的js文件里填入WebSocketURL:
使用外置Tomcat启动URL:ws://127.0.0.1:8088/WebSocketDemo_war/websocketapi
使用spring内置Tomcat启动URL:ws://127.0.0.1:8088/websocketapi
(注:因为在application.properties配置了端口使用8088,所以这里不是8080,如果application.properties没有配置,默认使用8080)
服务器也连接成功
使用Spring提供的低层级WebSocket API实现
在Controller包里新建类WebSocketConfig,添加代码。
"websocketapi"为ws的URL路径,可自行修改。
因为spring默认不接受跨域访问,设置setAllowedOrigins("*")允许接收跨域访问。
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(handler(), "websocketapi").setAllowedOrigins("*");
}
@Bean
public CustomizeWebSocketHandler handler() {
return new CustomizeWebSocketHandler();
}
}
在Controller包里新建类CustomizeWebSocketHandler ,添加代码
public class CustomizeWebSocketHandler extends TextWebSocketHandler {
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String payload = message.getPayload();
System.out.println("服务器接收到的数据:"+payload);
session.sendMessage(new TextMessage("服务器回复的消息: " + "Hello,Are you OK?"));
}
}
Jar包启动
代码添加完成后,直接点右上角选择DemoApplication启动。
war包启动
在Controller包里新建类WebSocketInitializer,添加代码。一开始启动后提示404,后来搜到了某位大佬的解决方法
public class WebSocketInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() { return null; }
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] {WebSocketConfig.class};
}
@Override
protected String[] getServletMappings() { return new String[] {"/"}; }
}
启动结果参考“使用@ServerEndpoint注解实现”的启动结果,URL也请参考上面的。这里一摸一样,就不再放了。Jar包启动时请把WebSocketInitializer注释掉(不注释也可以正常使用,个人觉得注释掉吧,以防止产生多余的bug)。