redis的发布订阅小结-websocket 多台tomcat集群解决方案

项目里用到了websocket 但是后台是tomcat集群 有时候就会发现前台没收到推送消息。发现websocket是用一个静态变量存的前后台连接。

百度发现解决方案有好多 选了个简单的 使用redis 发布订阅方式实现  就是后台收到需要推送的消息时就往redis发布一下。然后所有的tomcat都订阅他  就可以实现 集群不漏发的问题了。

一下是一些实现的代码和逻辑。

websocket代码、

package com.asdc.jbp.hisLogin.websocket;

import java.io.IOException;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.ContextLoader;



@Component("OutpatientDocWebSocket")
@ServerEndpoint("/outpatientDoc/{userId}")
public class OutpatientDocWebSocket {

	// concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
	//private static CopyOnWriteArraySet<OutpatientDocWebSocket> outpatientDocWebSocket = new CopyOnWriteArraySet<OutpatientDocWebSocket>();
	private static ConcurrentHashMap<String, OutpatientDocWebSocket> outpatientDocWebSocket = new ConcurrentHashMap<String, OutpatientDocWebSocket>();
	// 与某个客户端的连接会话,需要通过它来给客户端发送数据
	private Session session;
	
	//当前发消息的人员id
    private String userId = "";
    
    //保证当前连接是唯一的
    private String uniqueUuid = "";
	
    @Autowired
	private OutpatientRedisDao outpatientRedisDao;
	//=(OutpatientRedisDao) ContextLoader.getCurrentWebApplicationContext().getBean("OutpatientRedisDao")
	private Logger log=LoggerFactory.getLogger(getClass());

	/**
	 * 连接建立成功调用的方法
	 * @param session  可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
	 */
	@OnOpen
	public void onOpen(@PathParam(value = "userId") String paramUserId,Session session) {
		this.session = session;
		userId=paramUserId;
		uniqueUuid=UUID.randomUUID().toString();
		outpatientDocWebSocket.put(paramUserId, this); // 加入set中
		OutpatientRedisDao outpatientRedisDaoOnOpen=(OutpatientRedisDao) ContextLoader.getCurrentWebApplicationContext().getBean("OutpatientRedisDao");
		//广播建立连接 删除其他服务器连接
		outpatientRedisDaoOnOpen.sendMessageByOpen(OutpatientRedisDao.outpatientSocketOpenChannel, userId+"|"+uniqueUuid);
		   
	}

	/**
	 * 连接关闭调用的方法
	 */
	@OnClose
	public void onClose() {
		if(userId!=""){
			outpatientDocWebSocket.remove(userId); // 从map中删除
		}
		
	}

	/**
	 * 收到客户端消息后调用的方法
	 * @param message 客户端发送过来的消息
	 * @param session 可选的参数
	 */
	@OnMessage
	public void onMessage(String message, Session session) {
		//System.out.println("来自客户端的消息:" + message);
		//接受到的只能是websocket heart请求 不需理会
		//System.out.println(message);
		
	}

	/**
	 * 发生错误时调用
	 * @param session
	 * @param error
	 */
	@OnError
	public void onError(Session session, Throwable error) {
		//System.out.println("发生错误");
		log.error("websocket发生错误:",error);
		//error.printStackTrace();
	}

	/**
	 * 
	 * Description : 向前台发送消息 <br>
	 * Create Time: 2018年4月26日 <br>
	 * Create by : xxx<br>
	 *
	 * @param message
	 * @throws IOException
	 */
	public void sendMessage(String message) throws IOException {
		this.session.getBasicRemote().sendText(message);
	}


	/**
	 * 
	 * Description : 后台业务调用方法 <br>
	 * Create Time: 2018年5月7日 <br>
	 * Create by : xxx<br>
	 *
	 * @param regMsg
	 */
	public void SendRegisterMessage(String regMsg) {

		outpatientRedisDao.sendMessage(OutpatientRedisDao.outpatientChannel, regMsg);
		// 群发消息,向所有连接这个websocket服务器的客户端发送消息.
		
	}
	
	/**
	 * 
	 * Description : 接受redis回调的推送方法 <br>
	 * Create Time: 2018年5月7日 <br>
	 * Create by : xxx<br>
	 *
	 * @param callBackMsg
	 */
	public void sendMessageHandle(String callBackMsg){
		for (OutpatientDocWebSocket item : outpatientDocWebSocket.values()) {
			try {
				item.sendMessage(callBackMsg);
			} catch (IOException e) {
				log.error("websocket发送出错:",e);
				e.printStackTrace();
				continue;
			}
		}
	}
	
	/**
	 * 
	 * Description : 建立连接时删除当前已存在的连接---保持连接唯一 <br>
	 * Create Time: 2018年5月7日 <br>
	 * Create by : xxx<br>
	 *
	 * @param callBackMsg
	 */
	public void onOpenRemoveHandle(String callBackMsg){
		String[] msgs=callBackMsg.split("\\|");
		//0用户id  1 唯一标识uuid
		for (OutpatientDocWebSocket item : outpatientDocWebSocket.values()) {
			if(msgs[0].equals(item.userId)&&!msgs[1].equals(item.uniqueUuid)){
				outpatientDocWebSocket.remove(item.userId);
			}
		}
	}
	
}

监听redis订阅

package com.asdc.jbp.hisLogin.redisUtil;

import org.springframework.beans.factory.annotation.Autowired;



/**
 * 
 * ClassName : OutpatientDocMessageDelegateListenerImpl <br>
 * Description : 接受订阅默认代理-----由 MessageListenerAdapter  delegate  <br>
 * Create Time : 2018年4月26日 <br>
 * Create by : xxx<br>
 *
 */
public class OutpatientDocMessageDelegateListenerImpl{
	
	
	@Autowired
	private OutpatientDocWebSocket outpatientDocWebSocket;
	/**
	 * 
	 * Description : 此方法里实现订阅后调用方法 <br>
	 * Create Time: 2018年4月26日 <br>
	 * Create by : xxx<br>
	 *
	 * @param message
	 */
	public void handleMessage(String message){
		outpatientDocWebSocket.sendMessageHandle(message);
	}
	
	/**
	 * 
	 * Description : 连接时回调方法 <br>
	 * Create Time: 2018年5月9日 <br>
	 * Create by : xxx<br>
	 *
	 * @param message
	 */
	public void handleMessageByOpen(String message){
		outpatientDocWebSocket.onOpenRemoveHandle(message);
	}
}

 

往redis发布消息



public interface OutpatientRedisDao {
	public static final String outpatientChannel ="outpatientDoc_Channel";
	
	public static final String outpatientSocketOpenChannel="outpatientSocketOpen_Channel";
	
	/**
	 * 
	 * Description : 挂号发送医嘱列表信息 <br>
	 * Create Time: 2018年4月26日 <br>
	 * Create by : xxx <br>
	 *
	 * @param channel
	 * @param message
	 */
	public void sendMessage(String channel,String message);
	
	public void sendMessageByOpen(String channel,String message);
}


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

@Component("OutpatientRedisDao")
public class OutpatientRedisDaoImpl implements OutpatientRedisDao {

	@Autowired
	private StringRedisTemplate redisTemplate;
	
	@Override
	public void sendMessage(String channel, String message) {
		redisTemplate.convertAndSend(channel, message);
	}

	@Override
    public void sendMessageByOpen(String channel, String message) {
		redisTemplate.convertAndSend(channel, message);	    
    }

}

spring-redis配置

<bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
		<property name="connectionFactory" ref="jedisConnectionFactory" />
		<property name="keySerializer">
			<bean
				class="org.springframework.data.redis.serializer.StringRedisSerializer" />
		</property>
		<property name="valueSerializer">
			<bean
				class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
		</property>
		<property name="hashKeySerializer">
			<bean
				class="org.springframework.data.redis.serializer.StringRedisSerializer" />
		</property>
		<property name="hashValueSerializer">
			<bean
				class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
		</property>
	</bean>

<!-- 挂号医嘱列表 订阅发布  -->
    <bean id="outpatientMessageDelegateListener" class="com.OutpatientDocMessageDelegateListenerImpl" />
	
    <bean id="messageListener" class="org.springframework.data.redis.listener.adapter.MessageListenerAdapter">
        <property name="delegate" ref="outpatientMessageDelegateListener" />
        <property name="serializer" ref="serializer" />
    </bean>
    <!-- org.springframework.data.redis.serializer.StringRedisSerializer 会有乱码 -->
    <bean id="serializer" class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
    <redis:listener-container connection-factory="jedisConnectionFactory">
        <!-- the method attribute can be skipped as the default method name is "handleMessage" -->
        <redis:listener ref="outpatientMessageDelegateListener" serializer="serializer" method="handleMessage" topic="outpatientDoc_Channel" />
        <redis:listener ref="outpatientMessageDelegateListener" serializer="serializer" method="handleMessageByOpen" topic="outpatientSocketOpen_Channel" />
    </redis:listener-container>

代码还不是很完善 基本思路就这样。水平有限啊。。。。。

转载于:https://my.oschina.net/u/3065626/blog/1813081

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要下载tomcat-redis-session-manager-1.2-tomcat-7.jar,您可以按照以下步骤进行操作: 1. 打开您的网络浏览器,进入您通常使用的搜索引擎网站,如Google或百度。 2. 在搜索框中输入“tomcat-redis-session-manager-1.2-tomcat-7.jar下载”并按下回车键。 3. 检查搜索结果,找到可靠且权威的网站,比如Apache官方网站或者Maven中央库。 4. 点击打开所选网站,并在搜索栏中输入“tomcat-redis-session-manager-1.2-tomcat-7.jar”。 5. 您会看到相关的下载链接或页面,点击下载按钮或链接。 6. 选择一个合适的下载位置或文件夹,单击“保存”或“确认”按钮开始下载。 7. 等待下载完成,这可能需要一些时间,具体取决于您的网络连接速度和该文件的大小。 8. 下载完成后,在指定的下载位置或文件夹中找到下载的jar文件。 现在,您已经成功下载了tomcat-redis-session-manager-1.2-tomcat-7.jar文件,并可以将其用于相应的项目或应用程序中。请确保在使用该jar文件之前,仔细阅读相关的文档和说明,以确保正确配置和使用。 ### 回答2: 要下载tomcat-redis-session-manager-1.2-tomcat-7.jar,您可以按照以下步骤进行操作: 1. 打开您所用的网络浏览器(如Chrome、Firefox等)。 2. 在浏览器的地址栏中输入“tomcat-redis-session-manager-1.2-tomcat-7.jar”进行搜索。 3. 找到一个可信赖的下载来源,例如官方网站、GitHub等,确保文件来源可靠。 4. 点击下载链接或按钮,开始下载jar文件。 5. 下载完成后,您可以选择保存文件到您的电脑的特定目录,以便日后使用。 6. 如果您使用的是Tomcat服务器(版本7),则可以将该jar文件放置在您的Tomcat安装目录(通常是"tomcat7/lib"文件夹)下的“lib”文件夹中。 7. 确保您已经正确配置了Tomcat服务器,以便正确使用tomcat-redis-session-manager-1.2-tomcat-7.jar文件。 8. 现在,您已经成功下载并准备好使用tomcat-redis-session-manager-1.2-tomcat-7.jar文件了。 请注意,下载jar文件是一种常见的操作,确保您从可信赖的来源下载文件,以避免潜在的安全问题。另外,请根据您所使用的Tomcat服务器的版本选择正确的jar文件。 ### 回答3: 要下载 tomcat-redis-session-manager-1.2-tomcat-7.jar,您可以按照以下步骤进行操作: 1. 确定您的计算机上已安装 Java 运行时环境(JRE)和 Apache Tomcat 7。如果没有安装,您需要先下载和安装这些软件。 2. 打开您的网络浏览器,转到可信赖的软件下载网站,例如 Apache Tomcat 的官方网站或 Maven 仓库。 3. 在搜索框中输入 "tomcat-redis-session-manager-1.2-tomcat-7.jar",然后点击搜索按钮。 4. 在搜索结果中找到正确的版本,通常它会有与您正在使用的 Tomcat 版本相匹配的名称。 5. 单击下载按钮或链接,以开始下载该文件。文件大小可能会有所不同,所以可能需要一些时间来完成下载。 6. 一旦下载完成,将 jar 文件保存到您计算机上的合适位置,例如 Tomcat 的 lib 目录。 7. 确保您的 Tomcat 服务器已关闭。如果正在运行,请停止它。 8. 打开 Tomcat 的安装目录,找到和打开 conf 目录。 9. 在 conf 目录中找到 context.xml 文件,然后用文本编辑器打开。 10. 在 context.xml 文件中找到 `<Context>` 标签,并在其内部添加以下内容: ``` <Manager className="de.javakaffee.web.session.RedisSessionManager" host="localhost" port="6379" database="0" maxInactiveInterval="60" /> ``` 根据您的 Redis 服务器设置,可能需要进行其他自定义配置,例如主机名、端口号和数据库。 11. 保存并关闭 context.xml 文件。 12. 重新启动 Tomcat 服务器,以使更改生效。 现在,您已经成功下载了 tomcat-redis-session-manager-1.2-tomcat-7.jar,并将其集成到您的 Tomcat 服务器中。您可以使用 Redis 来存储和管理在 Tomcat 上运行的应用程序的会话。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值