Skip to content
Snippets Groups Projects
Commit 7aafc8d3 authored by Hoai Viet Nguyen's avatar Hoai Viet Nguyen
Browse files

implement full chat room function

parent c9dcfeb9
No related branches found
No related tags found
No related merge requests found
Showing
with 197 additions and 1 deletion
......@@ -24,10 +24,14 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-websocket'
implementation 'com.fasterxml.jackson.module:jackson-module-kotlin'
implementation 'org.jetbrains.kotlin:kotlin-reflect'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-validation'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.jetbrains.kotlin:kotlin-test-junit5'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'com.h2database:h2'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
implementation 'org.json:org.json:chargebee-1.0'
}
kotlin {
......
package de.thk.gm.websocketsdemo.configs
import de.thk.gm.websocketsdemo.handlers.ChatRoomsHandler
import de.thk.gm.websocketsdemo.handlers.EchoHandler
import de.thk.gm.websocketsdemo.handlers.SimpleChatHandler
import org.springframework.context.annotation.Configuration
......@@ -13,5 +14,6 @@ class WebSocketConfig () : WebSocketConfigurer {
override fun registerWebSocketHandlers(registry: WebSocketHandlerRegistry) {
registry.addHandler(EchoHandler(),"/echo")
registry.addHandler(SimpleChatHandler(),"/chat")
registry.addHandler(ChatRoomsHandler(),"/rooms")
}
}
\ No newline at end of file
package de.thk.gm.websocketsdemo.controllers
import de.thk.gm.websocketsdemo.dtos.ChatRoomDto
import de.thk.gm.websocketsdemo.models.ChatRoom
import de.thk.gm.websocketsdemo.services.ChatRoomsService
import org.springframework.stereotype.Controller
import org.springframework.ui.Model
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import java.util.*
@Controller
class ChatRoomsController (private var chatRoomsService: ChatRoomsService) {
@GetMapping("/chatrooms")
fun chatRooms(model: Model): String {
var chatRooms = chatRoomsService.findAll()
model.addAttribute("chatRooms", chatRooms)
return "chatRooms/showChatRooms"
}
@GetMapping("/chatrooms/{id}")
fun chatRoom(@PathVariable("id") id: UUID, model: Model): String {
var chatRoom = chatRoomsService.findById(id)
model.addAttribute("chatRoom", chatRoom)
return "chatRooms/showChatRoom"
}
@PostMapping("/chatrooms")
fun createChatRoom(chatRoomDto: ChatRoomDto): String {
var chatRoom = ChatRoom()
chatRoom.name = chatRoomDto.name
chatRoomsService.save(chatRoom)
return "redirect:/chatrooms/${chatRoom.id}"
}
}
\ No newline at end of file
package de.thk.gm.websocketsdemo.dtos
import jakarta.validation.constraints.Size
class ChatRoomDto {
@Size(min = 1, max = 100)
var name: String = ""
}
\ No newline at end of file
package de.thk.gm.websocketsdemo.handlers
import org.springframework.web.socket.CloseStatus
import org.springframework.web.socket.TextMessage
import org.springframework.web.socket.WebSocketSession
import org.springframework.web.socket.handler.TextWebSocketHandler
import org.springframework.web.util.UriComponents
import org.springframework.web.util.UriComponentsBuilder
import java.util.UUID
class ChatRoomsHandler : TextWebSocketHandler() {
private val hashMapOfSessions: HashMap<UUID, ArrayList<WebSocketSession>> = HashMap()
override fun afterConnectionEstablished(session: WebSocketSession) {
var uri: UriComponents = UriComponentsBuilder.fromUri(session.uri!!).build()
var roomId = UUID.fromString(uri.queryParams.getFirst("roomId"))
if (roomId != null) {
var sessions = hashMapOfSessions.get(roomId)
if (sessions == null) {
sessions = ArrayList()
}
sessions.add(session)
hashMapOfSessions[roomId] = sessions
}
}
override fun handleTextMessage(session: WebSocketSession, message: TextMessage) {
var uri: UriComponents = UriComponentsBuilder.fromUri(session.uri!!).build()
var roomId: UUID = UUID.fromString(uri.queryParams.getFirst("roomId"))
var sessions: ArrayList<WebSocketSession>? = hashMapOfSessions[roomId]
if (sessions != null) {
for (chatSession in sessions) {
chatSession.sendMessage(message)
}
}
}
override fun afterConnectionClosed(session: WebSocketSession, status: CloseStatus) {
var uri: UriComponents = UriComponentsBuilder.fromUri(session.uri!!).build()
var roomId: UUID? = UUID.fromString(uri.queryParams.getFirst("roomId"))
var sessions: ArrayList<WebSocketSession>? = hashMapOfSessions[roomId]
if (sessions != null && roomId != null) {
for (chatSession in sessions) {
if (chatSession.id == session.id) {
sessions.remove(chatSession)
hashMapOfSessions[roomId] = sessions
}
}
}
}
}
\ No newline at end of file
package de.thk.gm.websocketsdemo.models
import jakarta.persistence.Entity
import jakarta.persistence.Id
import java.util.*
@Entity
class ChatRoom {
@Id
var id: UUID = UUID.randomUUID()
var name: String = ""
}
\ No newline at end of file
package de.thk.gm.websocketsdemo.repositories
import de.thk.gm.websocketsdemo.models.ChatRoom
import org.springframework.data.repository.CrudRepository
import java.util.*
interface ChatRoomsRepository: CrudRepository<ChatRoom, UUID> {
}
\ No newline at end of file
package de.thk.gm.websocketsdemo.services
import de.thk.gm.websocketsdemo.models.ChatRoom
import org.springframework.stereotype.Service
import java.util.*
interface ChatRoomsService {
fun findAll(): List<ChatRoom>
fun findById(id: UUID): ChatRoom?
fun save(chatRoom: ChatRoom)
}
\ No newline at end of file
package de.thk.gm.websocketsdemo.services
import de.thk.gm.websocketsdemo.models.ChatRoom
import de.thk.gm.websocketsdemo.repositories.ChatRoomsRepository
import org.springframework.stereotype.Service
import java.util.*
@Service
class ChatRoomsServiceImpl (private val chatRoomsRepository: ChatRoomsRepository) : ChatRoomsService {
override fun findAll(): List<ChatRoom> {
return chatRoomsRepository.findAll().toList()
}
override fun findById(id: UUID): ChatRoom? {
return chatRoomsRepository.findById(id).orElse(null)
}
override fun save(chatRoom: ChatRoom) {
chatRoomsRepository.save(chatRoom)
}
}
\ No newline at end of file
<#import "../layout.ftlh" as base>
<@base.layout>
<h1>Chat room: ${chatRoom.name}</h1>
<div id="chat">
</div>
<input type="text" id="sender" placeholder="Max Mustermann"><br>
<input type="text" id="text" placeholder="Message...">
<button type="button" onclick="sendMessage()">Send</button>
<script>
var ws = new WebSocket("/rooms?roomId=${chatRoom.id}")
var chat = document.getElementById("chat")
ws.onmessage = function (message) {
var chatMessage = JSON.parse(message.data)
chat.innerHTML += "<p><b>" +chatMessage.sender+ "</b>:" + chatMessage.text + "</p>"
}
function sendMessage(){
var text = document.getElementById("text").value
var sender = document.getElementById("sender").value
var chatMessage = {"sender": sender, "text":text}
ws.send(JSON.stringify(chatMessage))
}
</script>
</@base.layout>
\ No newline at end of file
<#import "../layout.ftlh" as base>
<@base.layout>
<h2>Chat rooms</h2>
<ul>
<#list chatRooms as room>
<li><a href="/chatrooms/${room.id}">${room.name}</a></li>
</#list>
</ul>
<br>
<h2>Create chat room</h2>
<form action="/chatrooms" method="post">
<input type="text" name="name"><br>
<button>Create</button>
</form>
</@base.layout>
\ No newline at end of file
<#import "layout.ftlh" as base>
<#import "/spring.ftl" as spring />
<@base.layout>
<ul>
<li><a href="/echoclient.html">Echo Client</a></li>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment