技术解决方案
- 利用Redis的Pub/Sub
- 大致流程
- 前端发起WebSocket请求,建立连接后,后端把Session存至内存中。
- 当事件触发时,向Redis发送相对应的Topic和Message。
- 订阅此Topic的Listener会接受到消息,并从内存中查找相应的Session,如果找到Session则向前端推送消息。
- 具体代码Demo如下
@Configuration
public class RedisObserverConfig {
public static final String TOPIC_ORDER_FOOD = "websocket:order_food";
@Autowired
private JedisConnectionFactory jedisConnectionFactory;
@Bean
RedisMessageListenerContainer redisContainer() {
final RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(jedisConnectionFactory);
container.addMessageListener(messageListener(), orderFoodTopic());
container.setTaskExecutor(Executors.newFixedThreadPool(4));
return container;
}
@Bean
MessageListenerAdapter messageListener() {
return new MessageListenerAdapter(orderFoodListener());
}
@Bean
ChannelTopic orderFoodTopic() {
return new ChannelTopic(TOPIC_ORDER_FOOD);
}
@Bean
OrderDishesListener orderFoodListener() {
return new OrderDishesListener();
}
}
复制代码
<bean id="jedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
destroy-method="destroy">
<property name="hostName" value="${redis.host}" />
<property name="port" value="${redis.port}" />
<property name="timeout" value="${redis.timeout}" />
<property name="database" value="${redis.database}" />
<property name="password" value="${redis.password}" />
<property name="usePool" value="true" />
<property name="poolConfig" ref="jedisPoolConfig" />
</bean>
复制代码
- SendMessage
@Service
public class OrderFoodWebSocketService {
@Autowired
private RedisTemplate redisTemplate;
public void sendMessage() {
redisTemplate.convertAndSend(RedisObserverConfig.TOPIC_ORDER_FOOD, "hello");
}
}
复制代码
- MessageListener
public class OrderDishesListener implements MessageListener {
@Autowired
private RedisSerializer<Object> jsonRedisSerializer;
@Override
public void onMessage(Message message, byte[] pattern) {
Object object = jsonRedisSerializer.deserialize(message.getBody());
System.out.println("orderDishesListener message body = " + JSON.toJSONString(object));
}
}
复制代码
注意点
nginx支持WebSocket需要添加以下配置
location /wsapp/ {
proxy_pass http://wsbackend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
复制代码
nginx会把Http请求升级至WebSocket