WebSocket 协议在 2008 年诞生,2011 年成为国际标准。所有浏览器都已经支持了。
它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。
如何使用 OA 模块的 websocket
目前在项目源码中已经整合了 websocket
业务场景为: OA 模块,用户请假提交后,会自动根据流程通知上级。若上级在线在 前端的右上角会提示 有请假单需要处理。
如何开启使用:
①: vue.config.js 设置 ws 为 true,转发 ws 请求
②: index.vue 开启 websocket 相关的初始化
新增服务如何接入 websocket
① 添加 maven 依赖
新增 weboscket 配置类
@Slf4j
@Configuration
@RequiredArgsConstructor
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
private final ResourceServerTokenServices tokenService;
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").setAllowedOriginPatterns("*").withSockJS();
}
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(new ChannelInterceptor() {
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
// 判断是否首次连接请求
if (StompCommand.CONNECT.equals(accessor.getCommand())) {
// 处理租户
String tenant = accessor.getFirstNativeHeader(CommonConstants.TENANT_ID);
if (StrUtil.isNotBlank(tenant)) {
TenantContextHolder.setTenantId(Integer.parseInt(tenant));
}
else {
TenantContextHolder.setTenantId(CommonConstants.TENANT_ID_1);
}
// 验证令牌信息
String tokens = accessor.getFirstNativeHeader("Authorization");
log.info("webSocket token is {}", tokens);
if (StrUtil.isBlank(tokens)) {
return null;
}
OAuth2Authentication auth2Authentication = tokenService.loadAuthentication(tokens.split(" ")[1]);
if (ObjectUtil.isNotNull(auth2Authentication)) {
SecurityContextHolder.getContext().setAuthentication(auth2Authentication);
accessor.setUser(auth2Authentication::getName);
return message;
}
else {
return null;
}
}
// 不是首次连接,已经成功登陆
return message;
}
});
}
}
③ 对应微服务暴露 /ws/** 断点
④ 配置 gateway 网关路由,此处注意要新增两条路由规则。 由于是直接操作数据,注意重启 upms、网关
INSERT INTO sys_route_conf
(route_name
, route_id
, predicates
, filters
, uri
, order
, create_time
, update_time
, del_flag
) VALUES ( ‘demo模块’, ‘demo-biz-platform’, ‘[{"args": {"genkey0": "/demo/"}, "name": "Path"}]’, ‘[]’, ‘lb://demo-biz’, 0, ‘2021-01-06 09:00:58’, ‘2021-03-13 09:27:37’, ‘0’);
INSERT INTOsys_route_conf
( route_name
, route_id
, predicates
, filters
, uri
, order
, create_time
, update_time
, del_flag
) VALUES ( ‘demo工作流长链接支持2’, ‘demo-biz-ws-2’, ‘[{"args": {"genkey0": "/demo/ws/"}, "name": "Path"}]’, ‘[]’, ‘lb:ws://demo-biz’, 100, ‘2021-01-06 09:00:58’, ‘2021-03-13 09:27:52’, ‘0’);
⑤ 前端配置。
⑥ 后端发送消息
SimpMessagingTemplate simpMessagingTemplate = SpringContextHolder.getBean(SimpMessagingTemplate.class);
// 订阅通道 /task/租户ID/用户名称/remind
simpMessagingTemplate.convertAndSend("/task/1/admin/remind", "hello");