工程目录结构
springboot3-reactive
┣ src/main/java
┣ com.es.springboot3
┣ cache
┣ WebSocketClientCache.java
┣ config
┣ ApplicationConfiguration.java
┣ RedissonAutoConfiguration.java
┣ WebConfiguration.java
┣ WebSocketConfiguration.java
┣ context
┣ SpringContextHolder.java
┣ entity
┣ websocket
┣ WebSocketClient.java
┣ WebSocketMessageRecord.java
┣ event
┣ MessageEvent.java
┣ handler
┣ BroadcastWebSocketHandler.java
┣ P2MPWebSocketHandler.java
┣ P2PWebSocketHandler.java
┣ listener
┣ MessageListener.java
┣ properties
┣ RedissonProperty.java
┣ RedissonSentinel.java
┣ RedissonSingle.java
┣ SpringBoot3ReactiveApplication.java
┣ src/main/resources
┣ application.yml
┣ logback-spring.xml
┣ pom.xml
代码及配置
pom.xml
<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>
<groupId>com.es</groupId>
<artifactId>springboot3-reactive</artifactId>
<version>0.0.1-SNAPSHOT</version>
<description>响应式</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<spring-boot.version>3.0.0</spring-boot.version>
<hutool.version>5.8.10</hutool.version>
<fastjson.version>2.0.20</fastjson.version>
<redisson.version>3.18.0</redisson.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jakarta.websocket</groupId>
<artifactId>jakarta.websocket-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>${redisson.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<finalName>${project.name}</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<encoding>utf-8</encoding>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.es.springboot3.SpringBoot3ReactiveApplication</mainClass>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>
${project.build.directory}/lib
</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
application.yml
server:
port: 8009
application:
name: @artifactId@
version: @version@
spring:
application:
name: @artifactId@
redisson:
enabled: true
server: single
single:
address: redis://192.168.31.167:6379
connectionMinimumIdleSize: 5
connectionPoolSize: 50
password:
database: 14
timeout: 3000
SpringBoot3ReactiveApplication.java
package com.es.springboot3;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBoot3ReactiveApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBoot3ReactiveApplication.class, args);
}
}
WebSocketClientCache.java
package com.es.springboot3.cache;
import java.util.HashMap;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArraySet;
import org.redisson.api.RedissonClient;
import org.springframework.web.reactive.socket.WebSocketSession;
import com.es.springboot3.entity.websocket.WebSocketClient;
import lombok.experimental.UtilityClass;
@UtilityClass
public class WebSocketClientCache {
private static final ConcurrentMap<String, HashMap<String, WebSocketClient>> WEB_SOCKET_CLIENT_MAP = new ConcurrentHashMap<>();
public void setWebSocketClient(String source, WebSocketClient webSocketClient) {
HashMap<String, WebSocketClient> webSocketClientCache = WEB_SOCKET_CLIENT_MAP.get(source);
if (Objects.isNull(webSocketClientCache)) {
webSocketClientCache = new HashMap<>();
}
WebSocketSession session = webSocketClient.getSession();
if (Objects.nonNull(session)) {
webSocketClientCache.put(session.getId(), webSocketClient);
WEB_SOCKET_CLIENT_MAP.put(source, webSocketClientCache);
}
}
public HashMap<String,WebSocketClient> getWebSocketClient(String source){
return WEB_SOCKET_CLIENT_MAP.get(source);
}
public void delWebSocketClient(String source,String sessionId){
WEB_SOCKET_CLIENT_MAP.get(source).remove(sessionId);
}
}
ApplicationConfiguration.java
package com.es.springboot3.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
@Configuration(proxyBeanMethods = false)
@EnableAsync
public class ApplicationConfiguration {
}
RedissonAutoConfiguration.java
package com.es.springboot3.config;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.es.springboot3.properties.RedissonProperty;
import com.es.springboot3.properties.RedissonSentinel;
import com.es.springboot3.properties.RedissonSingle;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(RedissonProperty.class)
public class RedissonAutoConfiguration {
private final RedissonProperty conf;
@Bean(name = "redission", destroyMethod = "shutdown")
public RedissonClient redission() {
Config config = new Config();
config.setCodec(new org.redisson.client.codec.StringCodec());
if ("sentinel".equals(conf.getServer())) {
RedissonSentinel sentinel = conf.getSentinel();
config.useSentinelServers().setMasterName(sentinel.getMasterName())
.addSentinelAddress(sentinel.getSentinelAddresses()).setPassword(conf.getPassword())
.setDatabase(conf.getDatabase());
} else {
RedissonSingle single = conf.getSingle();
SingleServerConfig serverConfig = config.useSingleServer().setAddress(single.getAddress())
.setTimeout(conf.getTimeout()).setConnectionPoolSize(single.getConnectionPoolSize())
.setConnectionMinimumIdleSize(single.getConnectionMinimumIdleSize())
.setDatabase(conf.getDatabase());
if (StrUtil.isNotBlank(conf.getPassword())) {
serverConfig.setPassword(conf.getPassword());
}
}
return Redisson.create(config);
}
}
WebConfiguration.java
package com.es.springboot3.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.config.EnableWebFlux;
@Configuration(proxyBeanMethods = false)
@EnableWebFlux
public class WebConfiguration {
}
WebSocketConfiguration.java
package com.es.springboot3.config;
import java.util.HashMap;
import java.util.Map;
import org.redisson.api.RedissonClient;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping;
import org.springframework.web.reactive.socket.WebSocketHandler;
import org.springframework.web.reactive.socket.server.support.WebSocketHandlerAdapter;
import com.es.springboot3.handler.BroadcastWebSocketHandler;
import com.es.springboot3.handler.P2MPWebSocketHandler;
import com.es.springboot3.handler.P2PWebSocketHandler;
import lombok.RequiredArgsConstructor;
import reactor.core.publisher.Sinks;
@Configuration
@AutoConfigureAfter(RedissonAutoConfiguration.class)
@RequiredArgsConstructor
public class WebSocketConfiguration {
private final RedissonClient redissonClient;
@Bean
public SimpleUrlHandlerMapping webSocketHandlerMapping() {
Map<String,WebSocketHandler> webSocketHandlerMap = new HashMap<>();
webSocketHandlerMap.put("/ws/p2p", new P2PWebSocketHandler(redissonClient));
webSocketHandlerMap.put("/ws/p2mp", new P2MPWebSocketHandler(redissonClient));
webSocketHandlerMap.put("/ws/broadcast", new BroadcastWebSocketHandler(manySink()));
return new SimpleUrlHandlerMapping(webSocketHandlerMap, Ordered.HIGHEST_PRECEDENCE);
}
@Bean
public WebSocketHandlerAdapter webSocketHandlerAdapter() {
return new WebSocketHandlerAdapter();
}
@Bean
public Sinks.Many<String> manySink(){
return Sinks.many().multicast().directBestEffort();
}
}
SpringContextHolder.java
package com.es.springboot3.context;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
@Lazy(false)
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
private static ApplicationContext applicationContext = null;
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
SpringContextHolder.applicationContext = applicationContext;
}
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) {
return (T) applicationContext.getBean(name);
}
public static <T> T getBean(Class<T> requiredType) {
return applicationContext.getBean(requiredType);
}
public static void clearHolder() {
if (log.isDebugEnabled()) {
log.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);
}
applicationContext = null;
}
public static void publishEvent(ApplicationEvent event) {
if (applicationContext == null) {
return;
}
applicationContext.publishEvent(event);
}
@Override
@SneakyThrows
public void destroy() {
SpringContextHolder.clearHolder();
}
public static Object getProperty(String key) {
return getApplicationContext().getEnvironment().getProperty(key);
}
}
WebSocketClient.java
package com.es.springboot3.entity.websocket;
import java.io.Serializable;
import org.springframework.web.reactive.socket.WebSocketMessage;
import org.springframework.web.reactive.socket.WebSocketSession;
import lombok.AllArgsConstructor;
import lombok.Data;
import reactor.core.publisher.FluxSink;
@Data
@AllArgsConstructor
public class WebSocketClient implements Serializable {
private static final long serialVersionUID = 1L;
private FluxSink<WebSocketMessage> sink;
private WebSocketSession session;
public void sendMsg(String msg) {
sink.next(session.textMessage(msg));
}
}
WebSocketMessageRecord.java
package com.es.springboot3.entity.websocket;
import java.time.LocalDateTime;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
public record WebSocketMessageRecord(String msg, String source, String target, String targetType, LocalDateTime createTime) {
public static WebSocketMessageRecord trans(String message) {
JSONObject msgJSON = JSON.parseObject(message);
msgJSON.put("createTime", LocalDateTime.now());
return JSON.toJavaObject(msgJSON, WebSocketMessageRecord.class);
}
}
MessageEvent.java
package com.es.springboot3.event;
import org.springframework.context.ApplicationEvent;
public class MessageEvent extends ApplicationEvent{
private static final long serialVersionUID = 1L;
public MessageEvent(Object source) {
super(source);
}
}
BroadcastWebSocketHandler.java
package com.es.springboot3.handler;
import java.time.Duration;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.socket.WebSocketHandler;
import org.springframework.web.reactive.socket.WebSocketMessage;
import org.springframework.web.reactive.socket.WebSocketSession;
import com.es.springboot3.context.SpringContextHolder;
import com.es.springboot3.event.MessageEvent;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Mono;
import reactor.core.publisher.Sinks;
@Slf4j
@Component
@RequiredArgsConstructor
public class BroadcastWebSocketHandler implements WebSocketHandler {
public static ConcurrentHashMap<String, WebSocketSession> sessionBucket = new ConcurrentHashMap<>();
private final Sinks.Many<String> manySink;
@Override
public Mono<Void> handle(WebSocketSession session) {
sessionBucket.putIfAbsent(session.getId(), session);
Mono<Void> receiveMono = session.receive().map(WebSocketMessage::getPayloadAsText)
.doOnNext(data -> {
MessageEvent messageEvent = new MessageEvent(data);
SpringContextHolder.publishEvent(messageEvent);
manySink.emitNext(data, Sinks.EmitFailureHandler.FAIL_FAST);
}).then();
Mono<Void> sendMono = session
.send(Mono.delay(Duration.ofMillis(500)).thenMany(manySink.asFlux().map(msg -> session.textMessage(msg))))
.then();
return Mono.zip(receiveMono, sendMono).then();
}
}
P2MPWebSocketHandler.java
package com.es.springboot3.handler;
import java.net.InetSocketAddress;
import java.util.Map;
import org.redisson.api.RSet;
import org.redisson.api.RedissonClient;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.socket.HandshakeInfo;
import org.springframework.web.reactive.socket.WebSocketHandler;
import org.springframework.web.reactive.socket.WebSocketSession;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.http.HttpUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Slf4j
@Component
@RequiredArgsConstructor
public class P2MPWebSocketHandler implements WebSocketHandler {
private final RedissonClient redissonClient;
@Override
public Mono<Void> handle(WebSocketSession session) {
HandshakeInfo handshakeInfo = session.getHandshakeInfo();
InetSocketAddress remoteAddress = handshakeInfo.getRemoteAddress();
HttpHeaders headers = handshakeInfo.getHeaders();
String query = handshakeInfo.getUri().getQuery();
Map<String, String> paramMap = HttpUtil.decodeParamMap(query, CharsetUtil.CHARSET_UTF_8);
String userId = paramMap.get("userId");
String roomId = paramMap.get("roomId");
Mono<Void> receiveMono = session.receive().doOnSubscribe(conn -> {
log.info("建立连接:{},用户ip:{},房间id:{},用户:{}", session.getId(), remoteAddress.getHostName(), roomId, userId);
}).doOnComplete(() -> {
exitFromChatroom(roomId, userId);
log.info("doOnComplete关闭连接:{}", session.getId());
}).doOnCancel(() -> {
exitFromChatroom(roomId, userId);
log.info("doOnCancel关闭连接:{}", session.getId());
}).then();
Mono<Void> sendMono = session.send(Flux.create(sink -> entryToChatroom(roomId, userId)));
return Mono.zip(receiveMono, sendMono).then();
}
void entryToChatroom(String roomId, String userId) {
RSet<String> ids = redissonClient.getSet("chatroom:"+roomId);
ids.add(userId);
}
void exitFromChatroom(String roomId, String userId) {
RSet<String> ids = redissonClient.getSet("chatroom:"+roomId);
ids.remove(userId);
}
}
P2PWebSocketHandler.java
package com.es.springboot3.handler;
import java.net.InetSocketAddress;
import java.util.Map;
import org.redisson.api.RedissonClient;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.socket.HandshakeInfo;
import org.springframework.web.reactive.socket.WebSocketHandler;
import org.springframework.web.reactive.socket.WebSocketSession;
import com.es.springboot3.cache.WebSocketClientCache;
import com.es.springboot3.context.SpringContextHolder;
import com.es.springboot3.entity.websocket.WebSocketClient;
import com.es.springboot3.entity.websocket.WebSocketMessageRecord;
import com.es.springboot3.event.MessageEvent;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.http.HttpUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Slf4j
@Component
@RequiredArgsConstructor
public class P2PWebSocketHandler implements WebSocketHandler {
private final RedissonClient redissonClient;
@Override
public Mono<Void> handle(WebSocketSession session) {
HandshakeInfo handshakeInfo = session.getHandshakeInfo();
InetSocketAddress remoteAddress = handshakeInfo.getRemoteAddress();
HttpHeaders headers = handshakeInfo.getHeaders();
String query = handshakeInfo.getUri().getQuery();
Map<String, String> paramMap = HttpUtil.decodeParamMap(query, CharsetUtil.CHARSET_UTF_8);
String userId = paramMap.get("userId");
Mono<Void> receiveMono = session.receive().doOnSubscribe(conn -> {
log.info("建立连接:{},用户ip:{},用户:{}", session.getId(), remoteAddress.getHostName(), userId);
}).doOnNext(msg -> {
String data = msg.getPayloadAsText();
WebSocketMessageRecord messageRecord = WebSocketMessageRecord.trans(data);
sendP2P(messageRecord);
}).doOnComplete(() -> {
WebSocketClientCache.delWebSocketClient(userId, session.getId());
log.info("doOnComplete关闭连接:{},{}", userId, session.getId());
}).doOnCancel(() -> {
WebSocketClientCache.delWebSocketClient(userId, session.getId());
log.info("doOnCancel关闭连接:{},{}", userId, session.getId());
}).then();
Mono<Void> sendMono = session
.send(Flux.create(sink -> handleClient(userId, new WebSocketClient(sink, session))));
return Mono.zip(receiveMono, sendMono).then();
}
void handleClient(String source, WebSocketClient webSocketClient) {
WebSocketClientCache.setWebSocketClient(source, webSocketClient);
}
void sendP2P(WebSocketMessageRecord messageRecord) {
MessageEvent messageEvent = new MessageEvent(messageRecord);
SpringContextHolder.publishEvent(messageEvent);
}
}
MessageListener.java
package com.es.springboot3.listener;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import org.redisson.api.RReliableTopic;
import org.redisson.api.RSet;
import org.redisson.api.RedissonClient;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import com.es.springboot3.cache.WebSocketClientCache;
import com.es.springboot3.entity.websocket.WebSocketClient;
import com.es.springboot3.entity.websocket.WebSocketMessageRecord;
import com.es.springboot3.event.MessageEvent;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
@RequiredArgsConstructor
public class MessageListener {
private final RedissonClient redissonClient;
@PostConstruct
public void messageTopicListen() {
RReliableTopic messageTopic = redissonClient.getReliableTopic("messageTopic");
messageTopic.addListener(String.class, (channel, messageRecordObj) -> {
log.info("channel:{}", channel);
log.info("msg:{}", messageRecordObj);
WebSocketMessageRecord messageRecord = JSON.toJavaObject(JSON.parseObject(messageRecordObj), WebSocketMessageRecord.class);
String msg = JSON.toJSONString(messageRecord);
String source = messageRecord.source();
String target = messageRecord.target();
String targetType = messageRecord.targetType();
switch (targetType) {
case "SINGLE":
HashMap<String, WebSocketClient> sourceWebSocketClientMap = WebSocketClientCache.getWebSocketClient(source);
if (Objects.nonNull(sourceWebSocketClientMap)) {
sourceWebSocketClientMap.forEach((k, sourceWebSocketClient) -> {
sourceWebSocketClient.sendMsg(msg);
});
}
HashMap<String, WebSocketClient> targetWebSocketClientMap = WebSocketClientCache.getWebSocketClient(target);
if (Objects.nonNull(targetWebSocketClientMap)) {
targetWebSocketClientMap.forEach((k, targetWebSocketClient) -> {
targetWebSocketClient.sendMsg(msg);
});
}
break;
case "GROUP":
List<String> members = Arrays.asList("1", "2", "3");
members.parallelStream().forEach((id) -> {
HashMap<String, WebSocketClient> webSocketClientMap = WebSocketClientCache.getWebSocketClient(id);
if (Objects.nonNull(webSocketClientMap)) {
webSocketClientMap.forEach((k, webSocketClient) -> {
webSocketClient.sendMsg(msg);
});
}
});
break;
case "CHATROOM":
RSet<String> ids = redissonClient.getSet("chatroom:" + target);
ids.parallelStream().forEach((id) -> {
HashMap<String, WebSocketClient> webSocketClientMap = WebSocketClientCache.getWebSocketClient(id);
if (Objects.nonNull(webSocketClientMap)) {
webSocketClientMap.forEach((k, webSocketClient) -> {
webSocketClient.sendMsg(msg);
});
}
});
break;
}
});
}
@Async
@EventListener
public void messageListen(MessageEvent messageEvent) {
log.info("{}", JSON.toJSONString(messageEvent.getSource()));
WebSocketMessageRecord messageRecord = (WebSocketMessageRecord) messageEvent.getSource();
RReliableTopic messageTopic = redissonClient.getReliableTopic("messageTopic");
messageTopic.publish(JSON.toJSONString(messageRecord));
}
}
RedissonProperty.java
package com.es.springboot3.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import lombok.Data;
@Data
@ConfigurationProperties(prefix = "spring.redisson")
public class RedissonProperty {
private boolean enabled;
private String server;
private RedissonSingle single;
private RedissonSentinel sentinel;
private String password;
private int database;
private int timeout;
}
RedissonSentinel.java
package com.es.springboot3.properties;
import lombok.Data;
@Data
public class RedissonSentinel {
private int slaveConnectionPoolSize;
private int masterConnectionPoolSize;
private String[] sentinelAddresses;
private String masterName;
}
RedissonSingle.java
package com.es.springboot3.properties;
import lombok.Data;
@Data
public class RedissonSingle {
private String address;
private int connectionMinimumIdleSize;
private int connectionPoolSize;
}
客户端连接
postman
![在这里插入图片描述](https://img-blog.csdnimg.cn/3f30c5a3dbca499799927bf73d7a9eea.png)
创建连接
![在这里插入图片描述](https://img-blog.csdnimg.cn/a8c066be1fa141d899bd3cd511918980.png)
发送消息
![在这里插入图片描述](https://img-blog.csdnimg.cn/82c56a48c79a48f68bedc029139a9726.png)
接收消息
![在这里插入图片描述](https://img-blog.csdnimg.cn/c5808285d83643528bd823cf2fa9c8b9.png)