-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
[채팅] 레디스 연동 및 채팅 기능 개발
- Loading branch information
Showing
67 changed files
with
499 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# Websocket Simple Test | ||
|
||
1. ## Click `Edit Configurations...` | ||
![Edit-Configurations](editConfig.png) | ||
|
||
2. ## Input `local` in 'Active profiles' | ||
![Alt text](setProfile.png) | ||
|
||
> local 프로필로 실행하면 h2 db를 사용해 MySQL의 실행 없이 간단한 테스트가 가능합니다. | ||
3. ## Run! | ||
|
||
4. ## Open `front-test-bed/index.html` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
const stompClient = new StompJs.Client({ | ||
brokerURL: 'ws://localhost:8080/ws-stomp' | ||
}); | ||
|
||
// var channelId = "" | ||
|
||
stompClient.onConnect = (frame) => { | ||
setConnected(true); | ||
console.log('Connected: ' + frame); | ||
stompClient.subscribe('/sub/chat/channel/' + $("#channelId").val(), (message) => { | ||
console.log(JSON.parse(message.body)) | ||
showMessage(JSON.parse(message.body).content); | ||
}); | ||
}; | ||
|
||
stompClient.onWebSocketError = (error) => { | ||
console.error('Error with websocket', error); | ||
}; | ||
|
||
stompClient.onStompError = (frame) => { | ||
console.error('Broker reported error: ' + frame.headers['message']); | ||
console.error('Additional details: ' + frame.body); | ||
}; | ||
|
||
function setConnected(connected) { | ||
$("#connect").prop("disabled", connected); | ||
$("#disconnect").prop("disabled", !connected); | ||
if (connected) { | ||
$("#conversation").show(); | ||
} | ||
else { | ||
$("#conversation").hide(); | ||
} | ||
$("#greetings").html(""); | ||
} | ||
|
||
function connect() { | ||
stompClient.activate(); | ||
} | ||
|
||
function disconnect() { | ||
stompClient.deactivate(); | ||
setConnected(false); | ||
console.log("Disconnected"); | ||
} | ||
|
||
function sendName() { | ||
stompClient.publish({ | ||
destination: "/pub/chat/message", | ||
body: JSON.stringify( | ||
{ | ||
"channelId": $("#channelId").val(), | ||
"sender" : $("#name").val(), | ||
"content" : $("#content").val() | ||
} | ||
) | ||
}); | ||
} | ||
|
||
function showMessage(message) { | ||
$("#greetings").append("<tr><td>" + message + "</td></tr>"); | ||
} | ||
|
||
$(function () { | ||
$("form").on('submit', (e) => e.preventDefault()); | ||
$( "#connect" ).click(() => connect()); | ||
$( "#disconnect" ).click(() => disconnect()); | ||
$( "#send" ).click(() => sendName()); | ||
}); |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<title>Hello WebSocket</title> | ||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> | ||
<link href="/main.css" rel="stylesheet"> | ||
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script> | ||
<script src="https://cdn.jsdelivr.net/npm/@stomp/[email protected]/bundles/stomp.umd.min.js"></script> | ||
<script src="app.js"></script> | ||
</head> | ||
<body> | ||
<noscript><h2 style="color: #ff0000">Seems your browser doesn't support Javascript! Websocket relies on Javascript being | ||
enabled. Please enable | ||
Javascript and reload this page!</h2></noscript> | ||
<div id="main-content" class="container"> | ||
<div class="row"> | ||
<div class="col-md-6"> | ||
<form class="form-inline"> | ||
<div class="form-group"> | ||
<label for="connect">WebSocket connection:</label> | ||
<button id="connect" class="btn btn-default" type="submit">Connect</button> | ||
<button id="disconnect" class="btn btn-default" type="submit" disabled="disabled">Disconnect | ||
</button> | ||
</div> | ||
</form> | ||
</div> | ||
<div class="col-md-6"> | ||
<form class="form-inline"> | ||
<div class="form-group"> | ||
<label for="name">What is your name?</label> | ||
<input type="text" id="name" class="form-control" placeholder="Your name here..."> | ||
</div> | ||
</form> | ||
</div> | ||
<div class="col-md-6"> | ||
<form class="form-inline"> | ||
<div class="form-group"> | ||
<label for="name">Content</label> | ||
<input type="text" id="content" class="form-control" placeholder="Type your message..."> | ||
</div> | ||
<button id="send" class="btn btn-default" type="submit">Send</button> | ||
</form> | ||
</div> | ||
<div class="col-md-6"> | ||
<form class="form-inline"> | ||
<div class="form-group"> | ||
<label for="name">Set Channel Id</label> | ||
<input type="text" id="channelId" class="form-control" placeholder="Set temp ChannelId"> | ||
</div> | ||
</form> | ||
</div> | ||
</div> | ||
<div class="row"> | ||
<div class="col-md-12"> | ||
<table id="conversation" class="table table-striped"> | ||
<thead> | ||
<tr> | ||
<th>Greetings</th> | ||
</tr> | ||
</thead> | ||
<tbody id="greetings"> | ||
</tbody> | ||
</table> | ||
</div> | ||
</div> | ||
</div> | ||
</body> | ||
</html> |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file modified
0
sns_service/src/main/kotlin/joryu/sns_service/SnsServiceApplication.kt
100644 → 100755
Empty file.
35 changes: 35 additions & 0 deletions
35
sns_service/src/main/kotlin/joryu/sns_service/channel/entity/Channel.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package joryu.sns_service.channel.entity | ||
|
||
import jakarta.persistence.* | ||
import joryu.sns_service.channel.enums.ChannelType | ||
import java.io.Serializable | ||
import java.util.* | ||
|
||
|
||
@Table(name = "channel") | ||
@Entity | ||
class Channel( | ||
channelName: String = "", | ||
|
||
@Column(name = "channel_type") | ||
val channelType: ChannelType = ChannelType.PERSONAL | ||
) : Serializable { | ||
@Id | ||
@Column(name = "channel_id") | ||
val id: String = UUID.randomUUID().toString() | ||
|
||
@OneToMany(mappedBy = "channel") | ||
val channelProfiles: MutableList<ChannelProfile> = mutableListOf() | ||
|
||
@Column(name = "channel_name") | ||
var channelName: String = channelName | ||
private set | ||
|
||
fun updateChannelName(newName: String) { | ||
channelName = newName | ||
} | ||
|
||
fun addProfileToChannel(profile: ChannelProfile) { | ||
channelProfiles.add(profile) | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
sns_service/src/main/kotlin/joryu/sns_service/channel/entity/ChannelProfile.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package joryu.sns_service.channel.entity | ||
|
||
import jakarta.persistence.* | ||
import joryu.sns_service.profile.entity.Profile | ||
import java.io.Serializable | ||
|
||
@Table(name = "channel_profile") | ||
@Entity | ||
class ChannelProfile( | ||
@ManyToOne(fetch = FetchType.LAZY) | ||
@JoinColumn(name = "channel_id") | ||
val channel: Channel = Channel(), | ||
|
||
@ManyToOne(fetch = FetchType.LAZY) | ||
@JoinColumn(name = "profile_id") | ||
val profile: Profile = Profile() | ||
): Serializable { | ||
@Id | ||
@Column(name = "channel_profile_id") | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
val id: Long = 0 | ||
} |
5 changes: 5 additions & 0 deletions
5
sns_service/src/main/kotlin/joryu/sns_service/channel/enums/ChannelType.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package joryu.sns_service.channel.enums | ||
|
||
enum class ChannelType { | ||
PERSONAL, GROUP | ||
} |
7 changes: 7 additions & 0 deletions
7
sns_service/src/main/kotlin/joryu/sns_service/channel/repository/ChannelProfileRepository.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package joryu.sns_service.channel.repository | ||
|
||
import joryu.sns_service.channel.entity.ChannelProfile | ||
import org.springframework.data.jpa.repository.JpaRepository | ||
|
||
interface ChannelProfileRepository: JpaRepository<ChannelProfile, Long> { | ||
} |
7 changes: 7 additions & 0 deletions
7
sns_service/src/main/kotlin/joryu/sns_service/channel/repository/ChannelRepository.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package joryu.sns_service.channel.repository | ||
|
||
import joryu.sns_service.channel.entity.Channel | ||
import org.springframework.data.jpa.repository.JpaRepository | ||
|
||
interface ChannelRepository: JpaRepository<Channel, String> { | ||
} |
30 changes: 30 additions & 0 deletions
30
sns_service/src/main/kotlin/joryu/sns_service/chat/config/EmbeddedRedisConfig.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package joryu.sns_service.chat.config | ||
|
||
import jakarta.annotation.PostConstruct | ||
import jakarta.annotation.PreDestroy | ||
import org.springframework.beans.factory.annotation.Value | ||
import org.springframework.context.annotation.Configuration | ||
import org.springframework.context.annotation.Profile | ||
import redis.embedded.RedisServer | ||
|
||
|
||
@Profile("local") // profile이 local일때만 활성화 | ||
@Configuration | ||
class EmbeddedRedisConfig { | ||
|
||
@Value("\${spring.data.redis.port}") | ||
private val redisPort = 6379 | ||
|
||
private var redisServer: RedisServer? = null | ||
|
||
@PostConstruct | ||
fun redisServer() { | ||
redisServer = RedisServer(redisPort) | ||
redisServer?.start() | ||
} | ||
|
||
@PreDestroy | ||
fun stopRedis() { | ||
redisServer?.stop() | ||
} | ||
} |
86 changes: 86 additions & 0 deletions
86
sns_service/src/main/kotlin/joryu/sns_service/chat/config/RedisConfig.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package joryu.sns_service.chat.config | ||
|
||
import org.springframework.beans.factory.annotation.Qualifier | ||
import org.springframework.beans.factory.annotation.Value | ||
import org.springframework.context.annotation.Bean | ||
import org.springframework.context.annotation.Configuration | ||
import org.springframework.context.annotation.Primary | ||
import org.springframework.data.redis.connection.MessageListener | ||
import org.springframework.data.redis.connection.RedisConnectionFactory | ||
import org.springframework.data.redis.connection.RedisStandaloneConfiguration | ||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory | ||
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.listener.adapter.MessageListenerAdapter | ||
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories | ||
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer | ||
import org.springframework.data.redis.serializer.StringRedisSerializer | ||
|
||
|
||
/** | ||
* 채팅에 사용되는 redis 설정 관리 | ||
*/ | ||
@Configuration | ||
@EnableRedisRepositories | ||
class RedisConfig( | ||
@Value("\${spring.data.redis.port:6379}") | ||
private val port: Int, | ||
|
||
@Value("\${spring.data.redis.host:localhost}") | ||
private val host: String | ||
) { | ||
|
||
/** | ||
* ChannelTopic 에 발행된 메시지를 처리하는 Listner 들을 설정한다. | ||
*/ | ||
@Bean | ||
@Primary | ||
fun redisMessageListenerContainer( | ||
redisConnectionFactory: RedisConnectionFactory, | ||
chatMessageListenerAdapter: MessageListenerAdapter, | ||
@Qualifier("chatChannelTopic") chatChannelTopic: ChannelTopic | ||
): RedisMessageListenerContainer { | ||
val container = RedisMessageListenerContainer() | ||
container.setConnectionFactory(redisConnectionFactory) | ||
container.addMessageListener(chatMessageListenerAdapter, chatChannelTopic) | ||
return container | ||
} | ||
|
||
@Bean | ||
fun redisConnectionFactory(): RedisConnectionFactory { | ||
val redisStandaloneConfiguration = RedisStandaloneConfiguration() | ||
redisStandaloneConfiguration.hostName = host | ||
redisStandaloneConfiguration.port = port | ||
return LettuceConnectionFactory(redisStandaloneConfiguration) | ||
} | ||
|
||
/** | ||
* RedisMessageListenerContainer 로부터 메시지를 전달받는다. | ||
* 메시지 처리 비즈니스 로직을 담은 Subscriber Bean 을 추가해준다. | ||
*/ | ||
@Bean | ||
fun chatMessageListenerAdapter(listener: MessageListener): MessageListenerAdapter { | ||
return MessageListenerAdapter(listener, "onMessage") | ||
} | ||
|
||
/** | ||
* 채팅 채널 토픽을 반환한다. | ||
*/ | ||
@Bean(value = ["chatChannelTopic"]) | ||
fun chatChannelTopic(): ChannelTopic { | ||
return ChannelTopic("chat") | ||
} | ||
|
||
/** | ||
* Redis 데이터에 접근하는 redisTemplate 를 반환한다. | ||
*/ | ||
@Bean | ||
fun redisTemplate(connectionFactory: RedisConnectionFactory): RedisTemplate<String, Any> { | ||
val redisTemplate = RedisTemplate<String, Any>() | ||
redisTemplate.connectionFactory = connectionFactory | ||
redisTemplate.keySerializer = StringRedisSerializer() | ||
redisTemplate.valueSerializer = Jackson2JsonRedisSerializer(String::class.java) | ||
return redisTemplate | ||
} | ||
} |
Oops, something went wrong.