feat: 初始化
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>edu-websocket</artifactId>
|
||||
<groupId>com.yida.data.websocket</groupId>
|
||||
<version>2.2-RELEASE</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>edu-websocket-biz</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.yida.data.websocket</groupId>
|
||||
<artifactId>edu-websocket-api</artifactId>
|
||||
<version>2.2-RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<outputDirectory>../../../febs-jar</outputDirectory>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
+28
@@ -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);
|
||||
}
|
||||
}
|
||||
+61
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+36
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+38
@@ -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);
|
||||
}
|
||||
}
|
||||
+42
@@ -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";
|
||||
}
|
||||
}
|
||||
+46
@@ -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
|
||||
Reference in New Issue
Block a user