Java中Spring WebSocket详解
WebSockets是一种全双工、持久性的协议,能够在浏览器和服务器之间创建一个互动会话。Spring WebSocket简化了在Spring应用程序中使用WebSockets的流程。
使用Spring WebSocket
以下是使用Spring WebSocket的步骤:
- 在
pom.xml
文件中添加spring-boot-starter-websocket
依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
- 创建WebSocket配置类,并注入消息代理和“/endpoint”端点。
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
registry.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/endpoint").withSockJS();
}
}
- 创建WebSocket处理程序类,并实现
WebSocketHandler
接口。
@Component
public class WebSocketHandlerImpl implements WebSocketHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketHandlerImpl.class);
private List<WebSocketSession> sessions = new CopyOnWriteArrayList<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
LOGGER.info("New session connected {}", session.getId());
sessions.add(session);
}
@Override
public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
LOGGER.info("Message received {}", message.getPayload());
sendMessageToAll(message.getPayload());
}
private void sendMessageToAll(String message) throws IOException {
for (WebSocketSession session : sessions) {
session.sendMessage(new TextMessage(message));
}
}
}
- 创建控制器类,并使用
@MessageMapping
注解处理消息。
@Controller
public class WebSocketController {
private final WebSocketHandlerImpl webSocketHandler;
@Autowired
public WebSocketController(WebSocketHandlerImpl webSocketHandler) {
this.webSocketHandler = webSocketHandler;
}
@MessageMapping("/hello")
@SendTo("/topic/greetings")
public Greeting greeting(HelloMessage message) throws InterruptedException {
Thread.sleep(1000); // simulated delay
return new Greeting("Hello, " + message.getName() + "!");
}
}
- 在客户端JavaScript中创建WebSocket连接,并使用
stompClient
对象发送和接收消息。
var stompClient = null;
function connect() {
var socket = new SockJS('/endpoint');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/greetings', function (greeting) {
showGreeting(JSON.parse(greeting.body).content);
});
});
}
function sendName() {
var name = $('#name').val();
stompClient.send("/app/hello", {}, JSON.stringify({ 'name': name }));
}
接下来,详细介绍这个过程中的两个示例:
示例一:简单的Spring WebSocket应用程序
该示例演示了如何在Spring WebSocket应用程序中创建基本的WebSocket连接,并在服务器和客户端之间传输消息。
- 创建一个名为
Greeting
的Java类,表示要发送到客户端的消息。
public class Greeting {
private String content;
public Greeting(String content) {
this.content = content;
}
public String getContent() {
return content;
}
}
- 创建一个名为
HelloMessage
的Java类,表示从客户端发送到服务器的消息。
public class HelloMessage {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
- 创建一个名为
WebSocketController
的Spring控制器类,使用@MessageMapping
注解处理消息,并使用@SendTo
注解返回响应消息。
@Controller
public class WebSocketController {
@MessageMapping("/hello")
@SendTo("/topic/greetings")
public Greeting greeting(HelloMessage message) throws InterruptedException {
Thread.sleep(1000); // simulated delay
return new Greeting("Hello, " + message.getName() + "!");
}
}
- 创建
index.html
文件,并在其中向服务器发送消息并显示响应消息。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello WebSocket</title>
</head>
<body>
<form onsubmit="sendName(); return false;">
<input type="text" id="name" placeholder="Your name here..."/>
<button>Send</button>
</form>
<div id="greetings"></div>
<script src="/webjars/sockjs-client/1.0.2/sockjs.min.js"></script>
<script src="/webjars/stomp-websocket/2.3.3/stomp.min.js"></script>
<script src="/js/app.js"></script>
</body>
</html>
- 创建
app.js
文件,创建WebSocket连接并发送和接收消息。
var stompClient = null;
function connect() {
var socket = new SockJS('/endpoint');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/greetings', function (greeting) {
showGreeting(JSON.parse(greeting.body).content);
});
});
}
function sendName() {
var name = $('#name').val();
stompClient.send("/app/hello", {}, JSON.stringify({ 'name': name }));
}
function showGreeting(message) {
$('#greetings').append("<div>" + message + "</div>");
}
$(function () {
$('form').on('submit', function (e) {
e.preventDefault();
});
connect();
});
- 启动应用程序,并访问
http://localhost:8080
,向服务器发送消息并显示响应消息。
示例二:使用Spring Security的Spring WebSocket应用程序
该示例演示了如何在Spring WebSocket应用程序中使用Spring Security启用安全WebSocket连接。
- 添加
spring-boot-starter-security
依赖到pom.xml
文件中。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
- 在
WebSocketConfig
配置类中,配置WebSocket拦截器以启用Spring Security。
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Autowired
private CustomHandshakeHandler customHandshakeHandler;
@Autowired
private CustomWebSocketInterceptor customWebSocketInterceptor;
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat").setHandshakeHandler(customHandshakeHandler)
.addInterceptors(customWebSocketInterceptor).withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/queue/", "/topic/");
config.setApplicationDestinationPrefixes("/app");
}
}
- 创建
CustomHandshakeHandler
类,继承DefaultHandshakeHandler
类,以向用户签发令牌。
@Component
public class CustomHandshakeHandler extends DefaultHandshakeHandler {
@Autowired
private TokenUtils tokenUtils;
@Override
protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler,
Map<String, Object> attributes) {
String token = extractToken(request.getURI().toString());
return tokenUtils.getTokenOwner(token)::getId;
}
private String extractToken(String uri) {
// parse token from URI
}
}
- 创建
CustomWebSocketInterceptor
类,实现HandshakeInterceptor
接口,检查WebSocket握手请求是否有令牌。
@Component
public class CustomWebSocketInterceptor implements HandshakeInterceptor {
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
Map<String, Object> attributes) throws Exception {
String uri = request.getURI().toString();
String token = extractToken(uri);
if (StringUtils.isEmpty(token)) {
return false;
}
if (tokenIsValid(token)) {
return true;
}
return false;
}
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
Exception exception) {
}
private String extractToken(String uri) {
// parse token from URI
}
private boolean tokenIsValid(String token) {
// validate token
}
}
- 创建
TokenUtils
类,用于管理令牌。
@Component
public class TokenUtils {
public TokenUtils() {
// initialize token management
}
public User getTokenOwner(String token) {
// retrieve user from token
}
}
- 创建
WebSocketController
类,使用@MessageMapping
注解处理消息。
@Controller
public class WebSocketController {
@MessageMapping("/chat/{roomId}/message")
@SendTo("/topic/{roomId}")
public Message sendPrivateMessage(@DestinationVariable String roomId, Message message) throws Exception {
return message;
}
}
- 创建
Message
类,表示聊天消息。
public class Message {
private User from;
private String text;
public User getFrom() {
return from;
}
public void setFrom(User from) {
this.from = from;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
- 创建
User
类,表示WebSocket用户。
public class User {
private Long id;
private String name;
public User() {
}
public User(Long id, String name) {
this.id = id;
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
- 创建
index.html
文件,并在其中连接WebSocket并使用聊天。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>WebSocket Chat</title>
</head>
<body>
<script src="/webjars/sockjs-client/1.0.2/sockjs.min.js"></script>
<script src="/webjars/stomp-websocket/2.3.3/stomp.min.js"></script>
<form onsubmit="return false;">
<input type="text" id="message" placeholder="Message..." />
<input type="button" value="Send" onclick="sendMessage();" />
</form>
<div id="chat"></div>
<script th:inline="javascript">
var stompClient = null;
function connect() {
var socket = new SockJS('/chat');
stompClient = Stomp.over(socket);
var token = getTokenFromCookie(); // get user token from cookie
stompClient.connect({ 'Authorization': 'Bearer ' + token }, function (frame) {
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/chat', function (message) {
showMessage(JSON.parse(message.body));
});
});
}
function sendMessage() {
var message = $('#message').val();
stompClient.send('/app/chat/message', {}, JSON.stringify({ 'text': message }));
}
function showMessage(message) {
$('#chat').append('<div>' + message.from.name + ': ' + message.text + '</div>');
}
function getTokenFromCookie() {
// parse token from cookie
}
$(function () {
connect();
});
</script>
</body>
</html>
- 启动应用程序,并访问
http://localhost:8080
,连接WebSocket并开始聊天。
以上就是在Java中使用Spring WebSocket的完整攻略,以及两个示例的详细说明。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java中Spring WebSocket详解 - Python技术站