- Vue
- wsUrl:
- Sec-WebSocket-Protocol:
- webSocket = new WebSocket(wsUrl, Sec-WebSocket-Protocol)
- webSocket.onopen = function(){}
- webSocket.onmessage = function(){}
- webSocket.onclose = function(){}
- webSocket.onerror = function(){}
- heartCheck
- Nginx
http { upstream branchBackup { server 117.51.156.xxx:18081; server 117.51.156.xxx:28081 backup; } #后端平台管理系统接口 location ^~ /branch/api-v1/ws/ { proxy_pass http://branchBackup; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 86400s; proxy_send_timeout 86400s; } }
- ApplicationContext发布通知事件
- 发布事件
applicationContext.publishEvent(new ServiceNonstandardCheckEvent(this, id, checkStatus, serviceNonstandardEntity.getOperatorId()));
- 定义事件实体类(继承ApplicationEvent)
package com.das.listener.event.notification; import lombok.Getter; import lombok.Setter; import org.springframework.context.ApplicationEvent; /** * @Author liangmy * @Description: * @Create: 2021/1/19 上午11:26 */ @Getter @Setter public class ServiceNonstandardCheckEvent extends ApplicationEvent { /** * 询价服务唯一标志 */ private Long serviceNonstandardId; /** * 询价服务审核操作 * true :审核通过 * false : 审核拒绝 */ private Boolean checkStatus; /** * 通知接收账号唯一标志 */ private Long systemUserId; /** * Create a new ApplicationEvent. * * @param source the object on which the event initially occurred (never {@code null}) */ public ServiceNonstandardCheckEvent(Object source) { super(source); } public ServiceNonstandardCheckEvent(Object source, Long serviceNonstandardId, Boolean checkStatus, Long systemUserId) { super(source); this.serviceNonstandardId = serviceNonstandardId; this.checkStatus = checkStatus; this.systemUserId = systemUserId; } }
- 定义事件监听者(实现ApplicationListener<ApplicationEvent>)
package com.das.listener.notification; import com.alibaba.fastjson.JSON; import com.das.common.constant.EtcConstant; import com.das.common.constant.RedisPrefixConstant; import com.das.entity.system.NotificationEntity; import com.das.listener.event.notification.ServiceNonstandardCheckEvent; import com.das.service.notification.NotificationServiceManager; import com.das.service.redis.RedisService; import com.das.thirdParty.tim.TimService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; /** * @Author liangmy * @Description: * @Create: 2021/1/19 上午11:33 */ @Slf4j @Component public class ServiceNonstandardCheckListener implements ApplicationListener<ServiceNonstandardCheckEvent> { @Autowired private NotificationServiceManager notificationServiceManager; @Autowired private RedisService redisService; @Autowired private TimService timService; @Override public void onApplicationEvent(ServiceNonstandardCheckEvent event) { // 1. 持久化通知信息 log.info("saveNotificationAndReceiverForServiceNonstandarCheck(Long serviceNonstandardId, Boolean checkStatus, Long systemUserId) : {}, {}, {}", event.getServiceNonstandardId(), event.getCheckStatus(), event.getSystemUserId()); Long notificationId = notificationServiceManager.saveNotificationAndReceiverForServiceNonstandarCheck(event.getServiceNonstandardId(), event.getCheckStatus(), event.getSystemUserId()); if (EtcConstant.assertLegalParam(notificationId)) { // 2. 发布消息到 serviceNonstandarCheck 频道 NotificationEntity notificationEntity = new NotificationEntity(); notificationEntity.setId(notificationId); log.info("convertAndSend(RedisPrefixConstant.SubcribeTopic.serviceNonstandarCheck : {}", JSON.toJSONString(notificationEntity)); redisService.convertAndSend(RedisPrefixConstant.SubcribeTopic.serviceNonstandarCheck, notificationEntity); // 3. 发布消息到 IM log.info("sendmsgForServiceNonstandardCheck(Long systemUserId, Long serviceNonstandardId, Boolean checkStatus) : {}, {}, {}", event.getSystemUserId(), event.getServiceNonstandardId(), event.getCheckStatus()); timService.sendmsgForServiceNonstandardCheck(event.getSystemUserId(), event.getServiceNonstandardId(), event.getCheckStatus()); } } }
- 持久化通知信息
- 定义通知信息Subjoin类
package com.das.entity.system.notification; import lombok.Getter; import lombok.Setter; /** * @Author liangmy * @Description: * @Create: 2021/1/19 下午2:04 */ @Getter @Setter public class NotificationSubjoinServiceNonstandardCheckEntity { /** * 询价服务唯一标志 */ private Long serviceNonstandardId; /** * 询价服务审核状态 * true : 审核通过 * false : 审核拒绝 */ private Boolean checkStatus; /** * 询价服务创建人账号标志 */ private Long operatorId; }
- 持久化通知信息逻辑
/** * 持久化通知及通知接收人,并返回通知id(询价服务审核通过/审核拒绝) * * @param serviceNonstandardId * @param checkStatus * @param systemUserId 接收通知账号唯一标志 * @return */ @Override public Long saveNotificationAndReceiverForServiceNonstandarCheck(Long serviceNonstandardId, Boolean checkStatus, Long systemUserId) { if (!EtcConstant.assertLegalParam(serviceNonstandardId) || null == checkStatus) { throw DasException.internalError(null, messageSource.getMessage(EtcConstant.MessageCode.param_missing, null, LocaleContextHolder.getLocale())); } NotificationEntity notificationEntity = new NotificationEntity(); notificationEntity.setType(NotificationTypeEnum.SERVICE_NONSTANDAR_CHECK); notificationEntity.setContent(EtcConstant.WsMessage.NotificationConstant.content_service_nonstandar_check); NotificationSubjoinServiceNonstandardCheckEntity notificationSubjoinServiceNonstandardCheckEntity = new NotificationSubjoinServiceNonstandardCheckEntity(); notificationSubjoinServiceNonstandardCheckEntity.setServiceNonstandardId(serviceNonstandardId); notificationSubjoinServiceNonstandardCheckEntity.setCheckStatus(checkStatus); notificationEntity.setSubjoin(JSON.toJSONString(notificationSubjoinServiceNonstandardCheckEntity)); notificationMapper.save(notificationEntity); List<NotificationReceiverEntity> notificationReceiverEntityList = new LinkedList<>(); NotificationReceiverEntity notificationReceiverEntity = new NotificationReceiverEntity(); notificationReceiverEntity.setNotificationId(notificationEntity.getId()); SystemUserEntity systemUserEntity = systemUserService.getSysUser(systemUserId); if (null == systemUserEntity) { throw DasException.notAllowed(null, messageSource.getMessage(EtcConstant.MessageCode.system_user_not_exist, null, LocaleContextHolder.getLocale())); } String receiverKey = EtcConstant.getKey(systemUserId, systemUserEntity.getStoreBaseId()); notificationReceiverEntity.setReceiverKey(receiverKey); notificationReceiverEntityList.add(notificationReceiverEntity); notificationReceiverMappper.saveBatch(notificationReceiverEntityList); return notificationEntity.getId(); }
- 定义通知信息Subjoin类
- 发布消息到指定频道
- 定义Redis 发布订阅频道
/** * Redis 发布订阅频道 */ public static class SubcribeTopic { public static final String completeWork = "channel:ws:completeWork"; public static final String serviceNonstandarCheck = "channel:ws:serviceNonstandarCheck"; public static final String appointmentService = "channel:ws:appointmentService"; public static final String carPlanRemind = "channel:ws:carPlanRemind"; }
- 发布消息到 serviceNonstandarCheck 频道
NotificationEntity notificationEntity = new NotificationEntity(); notificationEntity.setId(notificationId); redisService.convertAndSend(RedisPrefixConstant.SubcribeTopic.serviceNonstandarCheck, notificationEntity);
- 定义Redis 发布订阅频道
- 持久化通知信息
- 发布事件
-
Redis 发布订阅模式
- 定义观察者RedisReceiver(实现org.springframework.data.redis.connection.MessageListener)
package com.das.listener.redis; import com.alibaba.fastjson.JSON; import com.das.common.constant.EtcConstant; import com.das.common.constant.RedisPrefixConstant; import com.das.entity.system.NotificationEntity; import com.das.mapper.system.NotificationMapper; import com.das.service.ws.WsMessageService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.data.redis.connection.Message; import org.springframework.data.redis.connection.MessageListener; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import java.util.LinkedList; import java.util.List; import java.util.concurrent.TimeUnit; /** * @Author liangmy * @Description: * @Create: 2020/11/4 下午7:35 */ @Slf4j @Component public class RedisReceiver implements MessageListener { @Autowired private ApplicationContext applicationContext; @Autowired private NotificationMapper notificationMapper; @Autowired private WsMessageService wsMessageService; @Override public void onMessage(Message message, byte[] bytes) { String channel = new String(message.getChannel()); String body = new String(message.getBody()); log.info("message.getChannel():{}", channel); log.info("message.getBody():{}", body); log.info("term:{}", EtcConstant.notificationTerm); body = body.substring(1, body.length() - 1); log.info("message.getBody():{}", body); NotificationEntity notificationEntity = JSON.parseObject(body, NotificationEntity.class); log.info("message.getBody()::parseObject:{}", JSON.toJSONString(notificationEntity)); log.info("notificationEntity.getId() : {}", notificationEntity.getId()); List<NotificationEntity> notificationEntityPushList = notificationMapper.getNotificationEntityPushList(notificationEntity.getId()); for (int i = 0; CollectionUtils.isEmpty(notificationEntityPushList) && i < 5; i++) { log.info("notificationMapper.getNotificationEntityPushList(notificationEntity.getId()) is empty, try again. times : {}. notificationEntity.getId() : {}", i, notificationEntity.getId()); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { log.info("notificationMapper.getNotificationEntityPushList(notificationEntity.getId()) sleep Interrupted. notificationEntity.getId() : {}", notificationEntity.getId()); } notificationEntityPushList = notificationMapper.getNotificationEntityPushList(notificationEntity.getId()); } List<String> alarmCountMessageOperatorKeyList = new LinkedList<>(); switch (channel) { case RedisPrefixConstant.SubcribeTopic.completeWork: case RedisPrefixConstant.SubcribeTopic.appointmentService: case RedisPrefixConstant.SubcribeTopic.carPlanRemind: case RedisPrefixConstant.SubcribeTopic.serviceNonstandarCheck: log.info("推送通知:{}", JSON.toJSONString(notificationEntityPushList)); wsMessageService.pushNotificationList(notificationEntityPushList); for (NotificationEntity notificationEntityAlarmCount : notificationEntityPushList) { alarmCountMessageOperatorKeyList.add(notificationEntityAlarmCount.getReceiverKey()); } wsMessageService.pushAlarmCountMessageList(alarmCountMessageOperatorKeyList); log.info("推送通知数量:{}", JSON.toJSONString(alarmCountMessageOperatorKeyList)); break; default: break; } } }
- 推送通知
@Override public void pushNotificationList(List<NotificationEntity> notificationEntityPushList) { WsMessageEntity wsMessageEntity = null; for (NotificationEntity notificationEntity : notificationEntityPushList) { String receiverKey = notificationEntity.getReceiverKey(); log.info("推送通知。获取接受人:{}", receiverKey); if (StringUtils.isBlank(receiverKey)) { continue; } log.info("推送通知。获取通知类型:{}", notificationEntity.getType()); notificationEntity.setTypeDesc(littleBear.getEnumValue(notificationEntity.getType())); log.info("parse Notification::subjoin : {}", notificationEntity.getSubjoin()); switch (notificationEntity.getType()) { case SERVICE_NONSTANDAR_CHECK: String downloadUrl = ""; NotificationSubjoinServiceNonstandardCheckEntity notificationSubjoinServiceNonstandardCheckEntity = JSON.parseObject(notificationEntity.getSubjoin(), NotificationSubjoinServiceNonstandardCheckEntity.class); if (null != notificationSubjoinServiceNonstandardCheckEntity) { SystemUserEntity systemUserEntity = systemUserMapper.getById(notificationSubjoinServiceNonstandardCheckEntity.getOperatorId()); if (null != systemUserEntity) { downloadUrl = ossService.getDownloadUrl(systemUserEntity.getPortraitResourceId()); notificationSubjoinServiceNonstandardCheckEntity.setOperatorImgUrl(downloadUrl); } } notificationEntity.setOperatorImgUrl(downloadUrl); notificationEntity.setSubjoin(JSON.toJSONString(notificationSubjoinServiceNonstandardCheckEntity)); notificationEntity.setSubjoinEntity(notificationSubjoinServiceNonstandardCheckEntity); break; default: break; } WsMessageTermEnum term = WsMessageTermEnum.valueOf(EtcConstant.notificationTerm); String receiverKeyTerm = EtcConstant.getKey(receiverKey, term); wsMessageEntity = new WsMessageEntity(WsMessageTypeEnum.notify, receiverKeyTerm); wsMessageEntity.setBodyClazz(notificationEntity.getClass().getName()); wsMessageEntity.setBody(notificationEntity); AbstractWebSocketServer.sendMsg(receiverKeyTerm, wsMessageEntity); log.info("通知推送。用户:{}, 通知:{}", receiverKeyTerm, JSON.toJSONString(wsMessageEntity)); } }
- 推送通知数量
@Override public void pushAlarmCountMessageList(List<String> alarmCountMessageOperatorKeyList) { for (String receiverKey : alarmCountMessageOperatorKeyList) { if (StringUtils.isBlank(receiverKey)) { continue; } // 所有类型通知数量 long getNonReadNofificationCount = notificationMapper.getNonReadNofificationCount(receiverKey); WsMessageTermEnum term = WsMessageTermEnum.valueOf(EtcConstant.notificationTerm); String receiverKeyTerm = EtcConstant.getKey(receiverKey, term); WsMessageEntity wsMessageEntity = new WsMessageEntity(WsMessageTypeEnum.message, receiverKeyTerm); wsMessageEntity.setBody(getNonReadNofificationCount); wsMessageEntity.setBodyClazz(EtcConstant.WsMessage.AlarmCount); AbstractWebSocketServer.sendMsg(receiverKeyTerm, wsMessageEntity); // 各个类型通知数量 List<LabelNonReadNofificationCountDO> labelNonReadNofificationCountList = notificationMapper.getLabelNonReadNofificationCount(receiverKey); Map<String, Integer> labelNonReadNofificationCount = new HashMap<>(); for (LabelNonReadNofificationCountDO labelNonReadNofificationCountDO : labelNonReadNofificationCountList) { labelNonReadNofificationCount.put(labelNonReadNofificationCountDO.getType().name(), labelNonReadNofificationCountDO.getAmount()); } wsMessageEntity.setBody(labelNonReadNofificationCount); wsMessageEntity.setBodyClazz(EtcConstant.WsMessage.labelNonReadNofificationCount); AbstractWebSocketServer.sendMsg(receiverKeyTerm, wsMessageEntity); } }
- 推送通知
- RedisConfig(继承CachingConfigurerSupport)
- JedisPool
- JedisPoolConfig
@Bean public JedisPool redisPoolFactory() { JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setMaxTotal(maxTotal); jedisPoolConfig.setMaxIdle(maxIdle); jedisPoolConfig.setMinIdle(minIdle); jedisPoolConfig.setMaxWaitMillis(maxWaitMillis); return new JedisPool(jedisPoolConfig, host, port, timeout, password); }
- JedisPoolConfig
- RedisTemplate
- StringRedisTemplate
private static final ObjectMapper om = new ObjectMapper(); @Bean public RedisTemplate redisTemplate(RedisConnectionFactory factory) { StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(factory); Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); stringRedisTemplate.setValueSerializer(jackson2JsonRedisSerializer); stringRedisTemplate.afterPropertiesSet(); return stringRedisTemplate; }
- Jackson2JsonRedisSerializer
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om);
- StringRedisTemplate
- MessageListenerAdapter
- RedisMessageListenerContainer
- MessageListener
- PatternTopic
- JedisPool
- 定义观察者RedisReceiver(实现org.springframework.data.redis.connection.MessageListener)
- 定义通知推送的终端
- notificationTerm=mech
- Filter
- 获取WS子协议
- String token = request.getHeader("Sec-WebSocket-Protocol");
- response.setHeader("Sec-WebSocket-Protocol", token);
- 获取WS子协议
- AbstractWebSocketService
- javax.websocket.Session
- @OnOpen
- @OnMessage
- @OnError
- @OnClose
- session.getBasicRemote().sendText(String text) throws IOException;
- WebSocketServiceImpl
- @Component
- @ServerEndpoint(value = "/ws/imServer/{term}")
- 啦啦啦
SpringBoot-WebSocket
最新推荐文章于 2023-12-22 14:39:55 发布