diff --git a/blog/chatting/server/src/main/java/com/example/chatting/config/RedisConfig.java b/blog/chatting/server/src/main/java/com/example/chatting/config/RedisConfig.java index 5eb42c18..5168fd03 100644 --- a/blog/chatting/server/src/main/java/com/example/chatting/config/RedisConfig.java +++ b/blog/chatting/server/src/main/java/com/example/chatting/config/RedisConfig.java @@ -1,6 +1,10 @@ package com.example.chatting.config; import com.example.chatting.redis.RedisSubscriber; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; @@ -11,7 +15,8 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.listener.ChannelTopic; import org.springframework.data.redis.listener.RedisMessageListenerContainer; -import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; +import org.springframework.data.redis.listener.adapter.MessageListenerAdapter; +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; @Slf4j @@ -27,6 +32,14 @@ public class RedisConfig { @Value("${spring.redis.password}") private String password; + @Bean + public ObjectMapper objectMapper() { + ObjectMapper mapper = new ObjectMapper(); + mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + mapper.registerModules(new JavaTimeModule(), new Jdk8Module()); + return mapper; + } + @Bean public RedisConnectionFactory redisConnectionFactory() { RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(); @@ -43,7 +56,7 @@ public class RedisConfig { RedisTemplate redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(connectionFactory); redisTemplate.setKeySerializer(new StringRedisSerializer()); - redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(String.class)); + redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer(objectMapper())); return redisTemplate; } @@ -52,7 +65,12 @@ public class RedisConfig { RedisSubscriber redisSubscriber) { RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.setConnectionFactory(connectionFactory); - container.addMessageListener(redisSubscriber, new ChannelTopic("message")); + container.addMessageListener(messageListenerAdapter(redisSubscriber), new ChannelTopic("message")); return container; } + + @Bean + public MessageListenerAdapter messageListenerAdapter(RedisSubscriber redisSubscriber) { + return new MessageListenerAdapter(redisSubscriber, "sendMessage"); + } } diff --git a/blog/chatting/server/src/main/java/com/example/chatting/config/WebSocketConfig.java b/blog/chatting/server/src/main/java/com/example/chatting/config/WebSocketConfig.java index cad54d0c..09911fa0 100644 --- a/blog/chatting/server/src/main/java/com/example/chatting/config/WebSocketConfig.java +++ b/blog/chatting/server/src/main/java/com/example/chatting/config/WebSocketConfig.java @@ -1,19 +1,28 @@ package com.example.chatting.config; +import com.example.chatting.handler.HandshakeHandler; +import com.example.chatting.handler.MessageHandler; +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 +@RequiredArgsConstructor @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { + private final MessageHandler messageHandler; + private final HandshakeHandler handshakeHandler; + @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/ws-stomp") .setAllowedOriginPatterns("*") + .setHandshakeHandler(handshakeHandler) .withSockJS(); } @@ -22,4 +31,9 @@ public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { registry.setApplicationDestinationPrefixes("/pub"); registry.enableSimpleBroker("/sub"); } + + @Override + public void configureClientInboundChannel(ChannelRegistration registration) { + registration.interceptors(messageHandler); + } } diff --git a/blog/chatting/server/src/main/java/com/example/chatting/controller/MessageController.java b/blog/chatting/server/src/main/java/com/example/chatting/controller/MessageController.java index d6f5c53a..3169ce0f 100644 --- a/blog/chatting/server/src/main/java/com/example/chatting/controller/MessageController.java +++ b/blog/chatting/server/src/main/java/com/example/chatting/controller/MessageController.java @@ -1,18 +1,62 @@ package com.example.chatting.controller; +import com.example.chatting.domain.dto.ChatMessage; import com.example.chatting.redis.RedisPublisher; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.ValueOperations; import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.security.Principal; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; @Controller @RequiredArgsConstructor public class MessageController { private final RedisPublisher redisPublisher; + private final RedisTemplate redisTemplate; + private final ObjectMapper objectMapper; @MessageMapping("/message") - public void message(String message) { - redisPublisher.publish("message", message); + public void message(Principal principal, ChatMessage chatMessage) throws JsonProcessingException { + System.out.println("controller"); + chatMessage.setSessionId(principal.getName()); + redisPublisher.publish("message", chatMessage); + } + + @ResponseBody + @GetMapping("/test") + public void test() { + ChatMessage chatMessage = new ChatMessage(); + chatMessage.setSessionId("session"); + chatMessage.setMessage("hello"); + + ChatMessage chatMessage2 = new ChatMessage(); + chatMessage2.setSessionId("session"); + chatMessage2.setMessage("hello"); + chatMessage2.setDate(LocalDateTime.now()); + + chatMessage2.setTestEnum(ChatMessage.TestEnum.A); + + List testList = new ArrayList<>(); + + testList.add(chatMessage); + testList.add(chatMessage2); + + ValueOperations ops = redisTemplate.opsForValue(); + ops.set("test", testList); + + List test = (List) ops.get("test"); + System.out.println("test = " + test); + +// redisPublisher.publish("message", chatMessage); } } diff --git a/blog/chatting/server/src/main/java/com/example/chatting/domain/dto/ChatMessage.java b/blog/chatting/server/src/main/java/com/example/chatting/domain/dto/ChatMessage.java new file mode 100644 index 00000000..15fe91c1 --- /dev/null +++ b/blog/chatting/server/src/main/java/com/example/chatting/domain/dto/ChatMessage.java @@ -0,0 +1,18 @@ +package com.example.chatting.domain.dto; + +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class ChatMessage { + + public enum TestEnum { + A, B, C + } + + private String sessionId; + private String message; + private LocalDateTime date; + private TestEnum testEnum; +} diff --git a/blog/chatting/server/src/main/java/com/example/chatting/handler/HandshakeHandler.java b/blog/chatting/server/src/main/java/com/example/chatting/handler/HandshakeHandler.java new file mode 100644 index 00000000..9212f09b --- /dev/null +++ b/blog/chatting/server/src/main/java/com/example/chatting/handler/HandshakeHandler.java @@ -0,0 +1,19 @@ +package com.example.chatting.handler; + +import org.springframework.http.server.ServerHttpRequest; +import org.springframework.stereotype.Component; +import org.springframework.web.socket.WebSocketHandler; +import org.springframework.web.socket.server.support.DefaultHandshakeHandler; + +import java.security.Principal; +import java.util.Map; +import java.util.UUID; + +@Component +public class HandshakeHandler extends DefaultHandshakeHandler { + + @Override + protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler, Map attributes) { + return new StompPrincipal(UUID.randomUUID().toString()); + } +} diff --git a/blog/chatting/server/src/main/java/com/example/chatting/handler/MessageHandler.java b/blog/chatting/server/src/main/java/com/example/chatting/handler/MessageHandler.java new file mode 100644 index 00000000..2a9d2aa7 --- /dev/null +++ b/blog/chatting/server/src/main/java/com/example/chatting/handler/MessageHandler.java @@ -0,0 +1,46 @@ +package com.example.chatting.handler; + +import com.example.chatting.domain.dto.ChatMessage; +import com.example.chatting.redis.RedisPublisher; +import lombok.RequiredArgsConstructor; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessageChannel; +import org.springframework.messaging.simp.SimpMessageType; +import org.springframework.messaging.simp.stomp.StompCommand; +import org.springframework.messaging.simp.stomp.StompHeaderAccessor; +import org.springframework.messaging.support.ChannelInterceptor; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class MessageHandler implements ChannelInterceptor { + + private final RedisPublisher redisPublisher; + + @Override + public Message preSend(Message message, MessageChannel channel) { + StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message); + + StompPrincipal simpUser = (StompPrincipal) accessor.getHeader("simpUser"); + System.out.println("simpUser = " + simpUser); + + String destination = accessor.getDestination(); + StompCommand command = accessor.getCommand(); + String sessionId = accessor.getSessionId(); + SimpMessageType messageType = accessor.getMessageType(); + + + if (accessor.getCommand() == StompCommand.SUBSCRIBE) { + System.out.println("destination = " + destination); + System.out.println("command = " + command); + System.out.println("sessionId = " + sessionId); + System.out.println("messageType = " + messageType); + ChatMessage chatMessage = new ChatMessage(); + chatMessage.setSessionId("session"); + chatMessage.setMessage("interceptor"); + redisPublisher.publish("message", chatMessage); + } + + return message; + } +} diff --git a/blog/chatting/server/src/main/java/com/example/chatting/handler/StompPrincipal.java b/blog/chatting/server/src/main/java/com/example/chatting/handler/StompPrincipal.java new file mode 100644 index 00000000..5e937b79 --- /dev/null +++ b/blog/chatting/server/src/main/java/com/example/chatting/handler/StompPrincipal.java @@ -0,0 +1,20 @@ +package com.example.chatting.handler; + +import lombok.ToString; + +import java.security.Principal; + +@ToString +public class StompPrincipal implements Principal { + + private final String name; + + public StompPrincipal(String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } +} diff --git a/blog/chatting/server/src/main/java/com/example/chatting/redis/RedisPublisher.java b/blog/chatting/server/src/main/java/com/example/chatting/redis/RedisPublisher.java index 04e29405..c17b6035 100644 --- a/blog/chatting/server/src/main/java/com/example/chatting/redis/RedisPublisher.java +++ b/blog/chatting/server/src/main/java/com/example/chatting/redis/RedisPublisher.java @@ -1,5 +1,6 @@ package com.example.chatting.redis; +import com.example.chatting.domain.dto.ChatMessage; import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; @@ -10,7 +11,7 @@ public class RedisPublisher { private final RedisTemplate redisTemplate; - public void publish(String topic, String message) { + public void publish(String topic, ChatMessage message) { redisTemplate.convertAndSend(topic, message); } } diff --git a/blog/chatting/server/src/main/java/com/example/chatting/redis/RedisSubscriber.java b/blog/chatting/server/src/main/java/com/example/chatting/redis/RedisSubscriber.java index 4f9ec449..91422ebc 100644 --- a/blog/chatting/server/src/main/java/com/example/chatting/redis/RedisSubscriber.java +++ b/blog/chatting/server/src/main/java/com/example/chatting/redis/RedisSubscriber.java @@ -1,10 +1,9 @@ package com.example.chatting.redis; +import com.example.chatting.domain.dto.ChatMessage; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.data.redis.connection.Message; -import org.springframework.data.redis.connection.MessageListener; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.messaging.simp.SimpMessageSendingOperations; import org.springframework.stereotype.Service; @@ -12,17 +11,17 @@ import org.springframework.stereotype.Service; @Slf4j @RequiredArgsConstructor @Service -public class RedisSubscriber implements MessageListener { +public class RedisSubscriber { private final ObjectMapper objectMapper; private final RedisTemplate redisTemplate; private final SimpMessageSendingOperations messagingTemplate; - @Override - public void onMessage(Message message, byte[] pattern) { + public void sendMessage(String message) { try { - String pubMessage = redisTemplate.getStringSerializer().deserialize(message.getBody()); - messagingTemplate.convertAndSend("/sub/message", pubMessage == null ? "" : pubMessage); + ChatMessage chatMessage = objectMapper.readValue(message, ChatMessage.class); + messagingTemplate.convertAndSend("/sub/message", chatMessage); +// messagingTemplate.convertAndSendToUser(chatMessage.getSessionId(), "/sub/message", chatMessage); } catch (Exception e) { log.error("Subscriber Error", e); } diff --git a/blog/chatting/server/src/main/resources/application.yml b/blog/chatting/server/src/main/resources/application.yml index e48383d4..2256613e 100644 --- a/blog/chatting/server/src/main/resources/application.yml +++ b/blog/chatting/server/src/main/resources/application.yml @@ -1,5 +1,10 @@ +server: + port: 28080 + + spring: redis: host: localhost port: 6379 - password: 1234 \ No newline at end of file + password: 1234 +