在上一篇文章中讲了如何在 SpringBoot
中配置 WebSocket
模拟实现群发消息的功能,本文则将进一步讲解如何在 SpringBoot
中配置基于 wss
协议和 STOMP
的 WebSocket
,本文假设你对 STOMP
协议有一定的了解,否则建议你先了解一下 STOMP
协议,可以参考这篇文章,此外不同于上一篇的代码示例比较复杂,本文将用尽可能少的代码为你展示效果,同样本文的完整代码已上传到GitHub,下面就正式开始。
同上一篇一样,在展示具体的代码配置之前,先展示一下最终的效果:
下面是整个项目的目录结构:
├─main
│ ├─java
│ │ └─com
│ │ └─zjw
│ │ └─stomp
│ │ │ StompApplication.java
│ │ │
│ │ ├─config
│ │ │ TomcatConfiguration.java
│ │ │ WebSocketConfig.java
│ │ │
│ │ └─controller
│ │ BroadcastController.java
│ │ HTMLController.java
│ │
│ └─resources
│ │ application.yaml
│ │ keystore.jks
│ │
│ └─templates
│ greet.html
│ index.html
│
└─test
└─java
└─com
└─zjw
└─stomp
StompApplicationTests.java
Tips
想要生成以上目录树的结构,只需要在命令行使用 tree /f 文件夹名
即可,如果不想展示具体的文件,去掉 /f
参数即可。
wss
配置想要设置 wss
协议只需要 SpringBoot
配置 https
即可,下面就讲解具体的步骤:
生成签名证书
在 cmd
中输入以下命令,这里的 D:\develop\keystore.jks
即证书的生成路径,自己根据自己的情况修改即可,之后回车,根据提示输入自己的信息,即可在设置的路径下生成证书文件。
keytool -genkeypair -alias tomcat -keyalg RSA -keystore D:\develop\keystore.jks
项目配置
首先复制刚才生成的 keystore.jks
文件,然后粘贴到 resources
文件夹下,完成后,修改application.yaml(yml)
文件:
server:
port: 443
ssl.key-store: classpath:keystore.jks
ssl.key-store-password: 123456
ssl.key-password: 123456
ssl.key-alias: tomcat
如果是 properties
文件,改成下列形式即可:
server.port=443
server.ssl.key-store=classpath:keystore.jks
server.ssl.key-store-password=123456
server.ssl.key-password=123456
server.ssl.key-alias=tomcat
Tomcat
配置
import org.apache.catalina.connector.Connector;
import org.apache.tomcat.websocket.server.WsSci;
import org.springframework.boot.web.embedded.tomcat.TomcatContextCustomizer;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class TomcatConfiguration {
@Bean
public ServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
tomcat.addAdditionalTomcatConnectors(createSslConnector());
return tomcat;
}
private Connector createSslConnector() {
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
connector.setScheme("http");
connector.setPort(8080);
connector.setSecure(false);
// 监听8080端口转发到443端口
connector.setRedirectPort(443);
return connector;
}
@Bean
public TomcatContextCustomizer tomcatContextCustomizer() {
return context -> context.addServletContainerInitializer(new WsSci(), null);
}
}
浏览器测试
完成以上步骤后,在浏览器中的地址栏中输入 https://localhost/
,只要能地址栏处显示不安全,就说明 https
配置成功:
STOMP
配置完成了 wss
也等于是 https
的配置后,就可以开始进行 STOMP
的配置了:
引入依赖
首先需要引入以下必要的依赖:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-websocketartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
<dependency>
<groupId>org.webjarsgroupId>
<artifactId>webjars-locatorartifactId>
<version>0.34version>
dependency>
<dependency>
<groupId>org.webjarsgroupId>
<artifactId>stomp-websocketartifactId>
<version>2.3.3version>
dependency>
配置广播的 Controller
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class BroadcastController {
// 这里的 @MessageMapping 可以当成 @RequestMapping,
// 当有信息(broardcast 方法中的 msg 参数即为客服端发送的信息)发送到 /sendMsg 时,
// broadcast 方法的返回的数据就会发送到所有订阅了 /broadcast/greet 的客户端
// 关于如何订阅 /broadcast/greet 会在之后的客户端代码看到
@MessageMapping("/sendMsg")
@SendTo("/broadcast/greet")
public String broadcast(String msg) {
return msg;
}
}
配置 WebSocket
消息代理
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
// 开启一个简单的基于内存的消息代理
// 将消息返回到订阅了带 /broadcast 前缀的目的客户端
// 上述的 @SendTo 中的地址需要带有 /broadcast 前缀
config.enableSimpleBroker("/broadcast");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
// 注册一个 /websocket 的 WebSocket 终端
registry.addEndpoint("/websocket");
}
}
视图解析 Controller
为了方便,项目在 templates
文件夹下建了 index.html
和 greet.html
,这里需要配置一下视图解析:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HTMLController {
@RequestMapping("/index")
public String index() {
return "index";
}
@RequestMapping("/greet")
public String greet() {
return "greet";
}
}
主页代码
<html lang="en">
<head>
<meta charset="UTF-8">
<title>主页title>
<script src="/webjars/stomp-websocket/stomp.min.js">script>
head>
<body>
<div id="greet">div>
<script>
// 设置 WebSocket 的连接地址 wss://localhost/websocket
let socket = new WebSocket('wss://localhost/websocket')
let stompClient = Stomp.over(socket)
stompClient.connect({}, function () {
// 订阅到 /broadcast/greet, 即 @SendTo 内配置的地址
stompClient.subscribe('/broadcast/greet', function (frame) {
// 获取消息帧的 body 内容, 显示到 中
showGreeting(`收到信息: ${frame.body}`)
})
})
function showGreeting(clientMessage) {
document.getElementById("greet").innerText += `${clientMessage}\n`
}
script>
body>
html>
发送消息界面的代码
<html lang="en">
<head>
<meta charset="UTF-8">
<title>群发信息title>
<script src="/webjars/stomp-websocket/stomp.min.js">script>
head>
<body>
<label><input type="text" id="msg"/>label>
<button onclick="sendMsg()">发送button>
<script>
// 设置 WebSocket 的连接地址 wss://localhost/websocket
let socket = new WebSocket('wss://localhost/websocket')
let stompClient = Stomp.over(socket);
function sendMsg() {
const msg = document.getElementById('msg').value
// 发送输入框内的信息, /sendMsg 即为 @MessageMapping 中配置的地址
stompClient.send("/sendMsg", {}, msg)
alert('发送成功')
}
script>
body>
html>
完成以上配置后,即可实现效果展示中的效果。
本文通过一个简单 demo
,展示了如何使用集成了 wss
和 STOMP
的 WebSocket
,希望能够对你有所帮助,之后还会再通过一些更具体完整的示例代码,来讲解 WebSocket
的具体应用。