Websocket redisクラスタインスタントメッセージチャットを実現
移動先:https://www.cnblogs.com/zwcry/p/9723447.html
Websocketとredismqはクラスタメッセージチャットを実現する
Websocketとredismqはクラスタメッセージチャットを実現する
1.application.properties server.port=8081
#thymeleaf
# 。
spring.thymeleaf.cache=false
# Web Thymeleaf 。
spring.thymeleaf.enabled=true
# SpringEL SpringEL 。
spring.thymeleaf.enable-spring-el-compiler=true
# 。
spring.thymeleaf.encoding=UTF-8
# 。 Thymeleaf TemplateMode 。
spring.thymeleaf.mode=HTML5
# URL 。
spring.thymeleaf.prefix=classpath:/templates/
#Content-Type HTTP 。
spring.thymeleaf.servlet.content-type=text/html
# URL 。
spring.thymeleaf.suffix=.html
##
spring.redis.host=192.168.159.129
##
spring.redis.port=6379
## ( )
spring.redis.pool.max-active=300
## Redis ( 0)
spring.redis.database=0
## ( )
spring.redis.pool.max-wait=-1
##
spring.redis.pool.max-idle=100
##
spring.redis.pool.min-idle=20
## ( )
spring.redis.timeout=60000
2.pom.xml
4.0.0
com.szw.learn
websocket_redis_mq_01
0.0.1-SNAPSHOT
websocket_redis_mq_01
org.springframework.boot
spring-boot-starter-parent
1.5.16.RELEASE
UTF-8
UTF-8
1.8
true
true
3.0.7.RELEASE
2.1.2
com.szw.learn.WsMqApplication
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-starter-thymeleaf
org.springframework.boot
spring-boot-starter-data-redis
org.springframework.boot
spring-boot-starter-websocket
nexus-aliyun
Nexus aliyun
http://maven.aliyun.com/nexus/content/groups/public
true
false
nexus-aliyun
Nexus aliyun
http://maven.aliyun.com/nexus/content/groups/public
true
false
org.apache.maven.plugins
maven-source-plugin
true
compile
jar
org.springframework.boot
spring-boot-maven-plugin
true
3.SpringUtils.java
package com.szw.learn.util;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Repository;
@Repository
public final class SpringUtils implements BeanFactoryPostProcessor {
private static ConfigurableListableBeanFactory beanFactory; // Spring
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
SpringUtils.beanFactory = beanFactory;
}
public static ConfigurableListableBeanFactory getBeanFactory() {
return beanFactory;
}
/**
*
*
* @param name
* @return Object bean
* @throws org.springframework.beans.BeansException
*
*/
@SuppressWarnings("unchecked")
public static T getBean(String name) throws BeansException {
return (T) getBeanFactory().getBean(name);
}
/**
* requiredType
*
* @param clz
* @return
* @throws org.springframework.beans.BeansException
*
*/
public static T getBean(Class clz) throws BeansException {
T result = (T) getBeanFactory().getBean(clz);
return result;
}
/**
* BeanFactory bean , true
*
* @param name
* @return boolean
*/
public static boolean containsBean(String name) {
return getBeanFactory().containsBean(name);
}
/**
* bean singleton prototype。 bean , (NoSuchBeanDefinitionException)
*
* @param name
* @return boolean
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
*
*/
public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
return getBeanFactory().isSingleton(name);
}
/**
* @param name
* @return Class
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
*
*/
public static Class> getType(String name) throws NoSuchBeanDefinitionException {
return getBeanFactory().getType(name);
}
/**
* bean bean ,
*
* @param name
* @return
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
*
*/
public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
return getBeanFactory().getAliases(name);
}
}
4.redis
service:
package com.szw.learn.redismq;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
/**
* @author : service
*/
@Component
public class PublishService {
@Autowired
StringRedisTemplate redisTemplate;
/**
* @author :
* @param channel
* @param message
*/
public void publish(String channel, Object message) {
// connection.publish(rawChannel, rawMessage);
redisTemplate.convertAndSend(channel, message);
}
}
リスニングクラスの購読:
package com.szw.learn.redismq;
import java.io.IOException;
import javax.websocket.Session;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.data.redis.core.StringRedisTemplate;
/**
* @author :
*/
public class SubscribeListener implements MessageListener {
private StringRedisTemplate stringRedisTemplate;
private Session session;
/**
*
*/
@Override
public void onMessage(Message message, byte[] pattern) {
String msg = new String(message.getBody());
System.out.println(new String(pattern) + " :" + msg);
if(null!=session){
try {
session.getBasicRemote().sendText(msg);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public StringRedisTemplate getStringRedisTemplate() {
return stringRedisTemplate;
}
public void setStringRedisTemplate(StringRedisTemplate stringRedisTemplate) {
this.stringRedisTemplate = stringRedisTemplate;
}
public Session getSession() {
return session;
}
public void setSession(Session session) {
this.session = session;
}
}
redis :
package com.szw.learn.redismq;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
@Configuration
public class RedisConfig {
@Autowired
private JedisConnectionFactory jedisConnectionFactory;
/**
* @author : RedisMessageListenerContainer IOC
* @return
*/
@Bean
public RedisMessageListenerContainer redisMessageListenerContainer() {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(jedisConnectionFactory);
return container;
}
}
5.websocket
Websocket登録:
package com.szw.learn.websocket;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebsocketConfig {
/**
*
: @Endpoint websocket ServerEndpointExporter
* @return
*/
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
Websocketエンドポイント:
package com.szw.learn.websocket;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.stereotype.Component;
import com.szw.learn.redismq.PublishService;
import com.szw.learn.redismq.SubscribeListener;
import com.szw.learn.util.SpringUtils;
/**
*@ServerEndpoint(value="/websocket")value /
* :@ServerEndpoint @Autowire
*{topic} :
*{myname} : 。
*/
@Component
@ServerEndpoint(value="/websocket/{topic}/{myname}")
public class WebsocketEndpoint {
/**
* @ServerEndpoint , SpringUtils IOC
*/
private StringRedisTemplate redisTampate = SpringUtils.getBean(StringRedisTemplate.class);
private RedisMessageListenerContainer redisMessageListenerContainer = SpringUtils.getBean(RedisMessageListenerContainer.class);
// ws 。 : ws 。
private static CopyOnWriteArraySet sessions = new CopyOnWriteArraySet<>();
private Session session;
@OnOpen
public void onOpen(Session session,@PathParam("topic")String topic){
System.out.println("java websocket: ");
this.session = session;
sessions.add(this);
SubscribeListener subscribeListener = new SubscribeListener();
subscribeListener.setSession(session);
subscribeListener.setStringRedisTemplate(redisTampate);
// topic
redisMessageListenerContainer.addMessageListener(subscribeListener, new ChannelTopic(topic));
}
@OnClose
public void onClose(Session session){
System.out.println("java websocket: ");
sessions.remove(this);
}
@OnMessage
public void onMessage(Session session,String message,@PathParam("topic")String topic,@PathParam("myname")String myname) throws IOException{
message = myname+":"+message;
System.out.println("java websocket =="+message);
PublishService publishService = SpringUtils.getBean(PublishService.class);
publishService.publish(topic, message);
}
@OnError
public void onError(Session session,Throwable error){
System.out.println("java websocket ");
}
public Session getSession() {
return session;
}
public void setSession(Session session) {
this.session = session;
}
}
テストコントロール
package com.szw.learn.websocket;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping("websocket")
public class WebsocketController {
@Value("${server.port}")
private String port;
public static final String INDEX = "websocket/index";
/**
* @author
* :
* @param topic
* @param myname
* @return
*/
@RequestMapping("index/{topic}/{myname}")
public ModelAndView index(@PathVariable("topic")String topic,@PathVariable("myname")String myname){
ModelAndView mav = new ModelAndView(INDEX);
mav.addObject("port", port);
mav.addObject("topic",topic);
mav.addObject("myname",myname);
return mav;
}
}
6.起動クラス
package com.szw.learn;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class WsMqApplication {
public static void main(String[] args) {
System.setProperty("spring.devtools.restart.enabled", "false");
SpringApplication.run(WsMqApplication.class, args);
}
}
7.テストページ
websocket
:[[${port}]], redismq websocket
[[${topic}]] 。。。
document.getElementById('input_id').focus();
var websocket = null;
// websocket
if("WebSocket" in window){
var url = "ws://127.0.0.1:[[${port}]]/websocket/[[${topic}]]/[[${myname}]]";
websocket = new WebSocket(url);
}else{
alert(" websocket");
}
websocket.onopen = function(event){
setMessage(" ");
}
websocket.onclose = function(event){
setMessage(" ");
}
websocket.onmessage = function(event){
setMessage(event.data);
}
websocket.onerror = function(event){
setMessage(" ");
}
// , , websocket , ,server 。
window.onbeforeunload = function(){
closeWebsocket();
}
// websocket
function closeWebsocket(){
//3
if(3!=websocket.readyState){
websocket.close();
}else{
alert("websocket ");
}
}
//
function setMessage(message){
document.getElementById('message_id').innerHTML += message + '<br/>';
}
//
function sendMessage(){
//1
if(1==websocket.readyState){
var message = document.getElementById('input_id').value;
//setMessage(message);
websocket.send(message);
}else{
alert("websocket ");
}
document.getElementById('input_id').value="";
document.getElementById('input_id').focus();
}
server.port=8081
#thymeleaf
# 。
spring.thymeleaf.cache=false
# Web Thymeleaf 。
spring.thymeleaf.enabled=true
# SpringEL SpringEL 。
spring.thymeleaf.enable-spring-el-compiler=true
# 。
spring.thymeleaf.encoding=UTF-8
# 。 Thymeleaf TemplateMode 。
spring.thymeleaf.mode=HTML5
# URL 。
spring.thymeleaf.prefix=classpath:/templates/
#Content-Type HTTP 。
spring.thymeleaf.servlet.content-type=text/html
# URL 。
spring.thymeleaf.suffix=.html
##
spring.redis.host=192.168.159.129
##
spring.redis.port=6379
## ( )
spring.redis.pool.max-active=300
## Redis ( 0)
spring.redis.database=0
## ( )
spring.redis.pool.max-wait=-1
##
spring.redis.pool.max-idle=100
##
spring.redis.pool.min-idle=20
## ( )
spring.redis.timeout=60000
4.0.0
com.szw.learn
websocket_redis_mq_01
0.0.1-SNAPSHOT
websocket_redis_mq_01
org.springframework.boot
spring-boot-starter-parent
1.5.16.RELEASE
UTF-8
UTF-8
1.8
true
true
3.0.7.RELEASE
2.1.2
com.szw.learn.WsMqApplication
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-starter-thymeleaf
org.springframework.boot
spring-boot-starter-data-redis
org.springframework.boot
spring-boot-starter-websocket
nexus-aliyun
Nexus aliyun
http://maven.aliyun.com/nexus/content/groups/public
true
false
nexus-aliyun
Nexus aliyun
http://maven.aliyun.com/nexus/content/groups/public
true
false
org.apache.maven.plugins
maven-source-plugin
true
compile
jar
org.springframework.boot
spring-boot-maven-plugin
true
package com.szw.learn.util;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Repository;
@Repository
public final class SpringUtils implements BeanFactoryPostProcessor {
private static ConfigurableListableBeanFactory beanFactory; // Spring
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
SpringUtils.beanFactory = beanFactory;
}
public static ConfigurableListableBeanFactory getBeanFactory() {
return beanFactory;
}
/**
*
*
* @param name
* @return Object bean
* @throws org.springframework.beans.BeansException
*
*/
@SuppressWarnings("unchecked")
public static T getBean(String name) throws BeansException {
return (T) getBeanFactory().getBean(name);
}
/**
* requiredType
*
* @param clz
* @return
* @throws org.springframework.beans.BeansException
*
*/
public static T getBean(Class clz) throws BeansException {
T result = (T) getBeanFactory().getBean(clz);
return result;
}
/**
* BeanFactory bean , true
*
* @param name
* @return boolean
*/
public static boolean containsBean(String name) {
return getBeanFactory().containsBean(name);
}
/**
* bean singleton prototype。 bean , (NoSuchBeanDefinitionException)
*
* @param name
* @return boolean
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
*
*/
public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
return getBeanFactory().isSingleton(name);
}
/**
* @param name
* @return Class
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
*
*/
public static Class> getType(String name) throws NoSuchBeanDefinitionException {
return getBeanFactory().getType(name);
}
/**
* bean bean ,
*
* @param name
* @return
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
*
*/
public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
return getBeanFactory().getAliases(name);
}
}
4.redis
service:
package com.szw.learn.redismq;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
/**
* @author : service
*/
@Component
public class PublishService {
@Autowired
StringRedisTemplate redisTemplate;
/**
* @author :
* @param channel
* @param message
*/
public void publish(String channel, Object message) {
// connection.publish(rawChannel, rawMessage);
redisTemplate.convertAndSend(channel, message);
}
}
package com.szw.learn.redismq;
import java.io.IOException;
import javax.websocket.Session;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.data.redis.core.StringRedisTemplate;
/**
* @author :
*/
public class SubscribeListener implements MessageListener {
private StringRedisTemplate stringRedisTemplate;
private Session session;
/**
*
*/
@Override
public void onMessage(Message message, byte[] pattern) {
String msg = new String(message.getBody());
System.out.println(new String(pattern) + " :" + msg);
if(null!=session){
try {
session.getBasicRemote().sendText(msg);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public StringRedisTemplate getStringRedisTemplate() {
return stringRedisTemplate;
}
public void setStringRedisTemplate(StringRedisTemplate stringRedisTemplate) {
this.stringRedisTemplate = stringRedisTemplate;
}
public Session getSession() {
return session;
}
public void setSession(Session session) {
this.session = session;
}
}
redis :
package com.szw.learn.redismq;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
@Configuration
public class RedisConfig {
@Autowired
private JedisConnectionFactory jedisConnectionFactory;
/**
* @author : RedisMessageListenerContainer IOC
* @return
*/
@Bean
public RedisMessageListenerContainer redisMessageListenerContainer() {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(jedisConnectionFactory);
return container;
}
}
package com.szw.learn.websocket;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebsocketConfig {
/**
*
: @Endpoint websocket ServerEndpointExporter
* @return
*/
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
package com.szw.learn.websocket;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.stereotype.Component;
import com.szw.learn.redismq.PublishService;
import com.szw.learn.redismq.SubscribeListener;
import com.szw.learn.util.SpringUtils;
/**
*@ServerEndpoint(value="/websocket")value /
* :@ServerEndpoint @Autowire
*{topic} :
*{myname} : 。
*/
@Component
@ServerEndpoint(value="/websocket/{topic}/{myname}")
public class WebsocketEndpoint {
/**
* @ServerEndpoint , SpringUtils IOC
*/
private StringRedisTemplate redisTampate = SpringUtils.getBean(StringRedisTemplate.class);
private RedisMessageListenerContainer redisMessageListenerContainer = SpringUtils.getBean(RedisMessageListenerContainer.class);
// ws 。 : ws 。
private static CopyOnWriteArraySet sessions = new CopyOnWriteArraySet<>();
private Session session;
@OnOpen
public void onOpen(Session session,@PathParam("topic")String topic){
System.out.println("java websocket: ");
this.session = session;
sessions.add(this);
SubscribeListener subscribeListener = new SubscribeListener();
subscribeListener.setSession(session);
subscribeListener.setStringRedisTemplate(redisTampate);
// topic
redisMessageListenerContainer.addMessageListener(subscribeListener, new ChannelTopic(topic));
}
@OnClose
public void onClose(Session session){
System.out.println("java websocket: ");
sessions.remove(this);
}
@OnMessage
public void onMessage(Session session,String message,@PathParam("topic")String topic,@PathParam("myname")String myname) throws IOException{
message = myname+":"+message;
System.out.println("java websocket =="+message);
PublishService publishService = SpringUtils.getBean(PublishService.class);
publishService.publish(topic, message);
}
@OnError
public void onError(Session session,Throwable error){
System.out.println("java websocket ");
}
public Session getSession() {
return session;
}
public void setSession(Session session) {
this.session = session;
}
}
package com.szw.learn.websocket;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping("websocket")
public class WebsocketController {
@Value("${server.port}")
private String port;
public static final String INDEX = "websocket/index";
/**
* @author
* :
* @param topic
* @param myname
* @return
*/
@RequestMapping("index/{topic}/{myname}")
public ModelAndView index(@PathVariable("topic")String topic,@PathVariable("myname")String myname){
ModelAndView mav = new ModelAndView(INDEX);
mav.addObject("port", port);
mav.addObject("topic",topic);
mav.addObject("myname",myname);
return mav;
}
}
package com.szw.learn;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class WsMqApplication {
public static void main(String[] args) {
System.setProperty("spring.devtools.restart.enabled", "false");
SpringApplication.run(WsMqApplication.class, args);
}
}
[[${topic}]] 。。。