feat: 初始化

This commit is contained in:
2024-04-09 11:34:46 +08:00
commit 39f3acc15f
3209 changed files with 253442 additions and 0 deletions
@@ -0,0 +1,28 @@
package com.yida.data.websocket;
import cc.mrbird.febs.common.security.starter.annotation.EnableFebsCloudResourceServer;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* @author MrBird
*/
@EnableAsync
@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)
@EnableFebsCloudResourceServer
@EnableTransactionManagement
@EnableScheduling
public class EduWebsocketApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(EduWebsocketApplication.class)
.web(WebApplicationType.SERVLET)
.run(args);
}
}
@@ -0,0 +1,61 @@
package com.yida.data.websocket.config;
import cn.hutool.core.collection.CollUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yida.data.common.core.entity.CurrentUser;
import java.util.LinkedHashMap;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.simp.stomp.StompCommand;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.messaging.support.MessageHeaderAccessor;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.stereotype.Component;
/**
* 连接鉴权
*/
@Slf4j
@Component
@Order(Ordered.HIGHEST_PRECEDENCE + 99)
@RequiredArgsConstructor
public class AuthIntercentor implements ChannelInterceptor {
private final ResourceServerTokenServices resourceServerTokenServices;
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
//判断是否首次连接
if (accessor != null && StompCommand.CONNECT.equals(accessor.getCommand())) {
List<String> authorization = accessor.getNativeHeader("Authorization");
log.info("websocket认证:[{}]", authorization);
boolean isLogin = false;
if (CollUtil.isNotEmpty(authorization)) {
try {
OAuth2Authentication oAuth2Authentication = resourceServerTokenServices
.loadAuthentication(authorization.get(0));
LinkedHashMap<String, Object> authenticationDetails = (LinkedHashMap<String, Object>) oAuth2Authentication
.getUserAuthentication().getDetails();
Object principal = authenticationDetails.get("principal");
ObjectMapper mapper = new ObjectMapper();
CurrentUser currentUser = mapper.readValue(mapper.writeValueAsString(principal), CurrentUser.class);
log.info("获取到用户:[{}]", currentUser);
isLogin = true;
} catch (Exception e) {
log.error("错误:", e);
}
}
return isLogin ? message : null;
}
return message;
}
}
@@ -0,0 +1,36 @@
package com.yida.data.websocket.config;
import com.rabbitmq.client.Channel;
import com.yida.data.msg.dto.WebsocketMsgDTO;
import com.yida.data.rabbit.constant.RabbitConstant;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.SimpMessagingTemplate;
@Slf4j
@Configuration
@RequiredArgsConstructor
public class RabbitReceiver {
private final SimpMessagingTemplate simpMessagingTemplate;
@RabbitListener(bindings = @QueueBinding(
value = @Queue(RabbitConstant.MSG_WEBSOCKET_QUEUE),
exchange = @Exchange(RabbitConstant.MSG_EXCHANGE)
))
public void receivePosition(WebsocketMsgDTO msg, Channel channel, Message message) {
long deliveryTag = message.getMessageProperties().getDeliveryTag();
try {
simpMessagingTemplate.convertAndSendToUser(msg.getUserId().toString(), "/msg", msg.getContent());
channel.basicAck(deliveryTag, false);
} catch (Exception e) {
log.error("推送websocket失败", e);
}
}
}
@@ -0,0 +1,38 @@
package com.yida.data.websocket.config;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
@Configuration
@EnableWebSocketMessageBroker
@RequiredArgsConstructor
public class StompConfig implements WebSocketMessageBrokerConfigurer {
private final AuthIntercentor authIntercentor;
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
// 配置客户端尝试连接地址
registry.addEndpoint("/out/connect").setAllowedOrigins("*").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
// 设置广播节点
registry.enableSimpleBroker("/topic", "/user");
// 客户端向服务端发送消息需有/app 前缀
registry.setApplicationDestinationPrefixes("/app");
// 指定用户发送(一对一)的前缀 /user/
registry.setUserDestinationPrefix("/user/");
}
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(authIntercentor);
}
}
@@ -0,0 +1,42 @@
package com.yida.data.websocket.controller;
import com.yida.data.common.core.common.ResultBean;
import lombok.RequiredArgsConstructor;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/in/msg")
@RequiredArgsConstructor
public class WsController {
private final SimpMessagingTemplate simpMessagingTemplate;
@MessageMapping("/hello")
@SendTo("/topic/hello")
public ResultBean<String> hello(String requestMessage) {
System.out.println("接收消息:" + requestMessage);
return ResultBean.buildSuccess("服务端接收到你发的:" + requestMessage);
}
@GetMapping("/sendMsgByUser")
public Object sendMsgByUser(String token, String msg) {
simpMessagingTemplate.convertAndSendToUser(token, "/msg", msg);
return "success";
}
@GetMapping("/sendMsgByAll")
public Object sendMsgByAll(String msg) {
simpMessagingTemplate.convertAndSend("/topic", msg);
return "success";
}
@GetMapping("/test")
public String test() {
return "test-stomp.html";
}
}
@@ -0,0 +1,46 @@
package com.yida.data.websocket.util;
import cn.hutool.core.util.StrUtil;
import java.util.concurrent.ConcurrentHashMap;
import lombok.extern.slf4j.Slf4j;
/**
* websocket连接管理
*/
@Slf4j
public class SessionManager {
private final static ConcurrentHashMap<Long, String> USER_TOKEN = new ConcurrentHashMap<>();
private final static ConcurrentHashMap<String, Long> TOKEN_USER = new ConcurrentHashMap<>();
public static void add(Long userId, String token) {
USER_TOKEN.put(userId, token);
TOKEN_USER.put(token, userId);
}
public static void del(Long userId) {
String token = USER_TOKEN.get(userId);
if (StrUtil.isNotBlank(token)) {
USER_TOKEN.remove(userId);
TOKEN_USER.remove(token);
}
}
public static void del(String token) {
Long userId = TOKEN_USER.get(token);
if (userId != null) {
USER_TOKEN.remove(userId);
TOKEN_USER.remove(token);
}
}
public static Boolean exist(Long userId) {
String token = USER_TOKEN.get(userId);
return USER_TOKEN.containsKey(userId) && TOKEN_USER.containsKey(token);
}
public static Boolean exist(String token) {
Long userId = TOKEN_USER.get(token);
return USER_TOKEN.containsKey(userId) && TOKEN_USER.containsKey(token);
}
}
@@ -0,0 +1,32 @@
spring:
elasticsearch:
profiles:
active: "@env-name@"
application:
name: Edu-Websocket
cloud:
nacos:
config:
server-addr: ${nacos.url}
group: DEFAULT_GROUP
prefix: edu-websocket
file-extension: yaml
refreshable-dataids:
discovery:
server-addr: ${nacos.url}
logging:
level:
org:
springframework:
boot:
actuate:
endpoint:
EndpointId: error
com:
alibaba:
cloud:
nacos:
client:
NacosPropertySourceBuilder: error