Merge pull request 'feature/back' (#13) from feature/back into feature/all

Reviewed-on: #13
This commit is contained in:
ExostFlash 2025-06-03 06:27:27 +00:00
commit c72d6e2b99
10 changed files with 286 additions and 28 deletions

View file

@ -0,0 +1,30 @@
package fr.teamflash.fencerjudgeback.config
import org.springframework.context.annotation.Configuration
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
const val CHANNEL_MATCH_NAME: String = "/ws/topic/match"
@Configuration
@EnableWebSocketMessageBroker
open class MatchWebSocketConfig : WebSocketMessageBrokerConfigurer {
override fun configureMessageBroker(registry: MessageBrokerRegistry) {
// Enable a simple memory-based message broker to send messages to clients
// Prefix for messages FROM server TO client
registry.enableSimpleBroker(CHANNEL_MATCH_NAME)
// Prefix for messages FROM client TO server
registry.setApplicationDestinationPrefixes("/ws/matches")
}
override fun registerStompEndpoints(registry: StompEndpointRegistry) {
// Register the "/ws" endpoint, enabling SockJS fallback options
registry.addEndpoint("/ws/matches-app")
.setAllowedOriginPatterns("*") // Allow connections from any origin (adjust for production)
.withSockJS()
}
}

View file

@ -6,16 +6,16 @@ import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBr
import org.springframework.web.socket.config.annotation.StompEndpointRegistry import org.springframework.web.socket.config.annotation.StompEndpointRegistry
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer
const val CHANNEL_NAME: String = "/ws/topic" const val CHANNEL_PLAYER_NAME: String = "/ws/topic/match"
@Configuration @Configuration
@EnableWebSocketMessageBroker @EnableWebSocketMessageBroker
open class WebSocketConfig : WebSocketMessageBrokerConfigurer { open class PlayerWebSocketConfig : WebSocketMessageBrokerConfigurer {
override fun configureMessageBroker(registry: MessageBrokerRegistry) { override fun configureMessageBroker(registry: MessageBrokerRegistry) {
// Enable a simple memory-based message broker to send messages to clients // Enable a simple memory-based message broker to send messages to clients
// Prefix for messages FROM server TO client // Prefix for messages FROM server TO client
registry.enableSimpleBroker(CHANNEL_NAME) registry.enableSimpleBroker(CHANNEL_PLAYER_NAME)
// Prefix for messages FROM client TO server // Prefix for messages FROM client TO server
registry.setApplicationDestinationPrefixes("/ws") registry.setApplicationDestinationPrefixes("/ws")
@ -23,7 +23,7 @@ open class WebSocketConfig : WebSocketMessageBrokerConfigurer {
override fun registerStompEndpoints(registry: StompEndpointRegistry) { override fun registerStompEndpoints(registry: StompEndpointRegistry) {
// Register the "/ws" endpoint, enabling SockJS fallback options // Register the "/ws" endpoint, enabling SockJS fallback options
registry.addEndpoint("/ws/matches-app") registry.addEndpoint("/ws/players-app")
.setAllowedOriginPatterns("*") // Allow connections from any origin (adjust for production) .setAllowedOriginPatterns("*") // Allow connections from any origin (adjust for production)
.withSockJS() .withSockJS()
} }

View file

@ -0,0 +1,30 @@
package fr.teamflash.fencerjudgeback.config
import org.springframework.context.annotation.Configuration
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
const val CHANNEL_REFEREE_NAME: String = "/ws/topic/referee"
@Configuration
@EnableWebSocketMessageBroker
open class RefereeWebSocketConfig : WebSocketMessageBrokerConfigurer {
override fun configureMessageBroker(registry: MessageBrokerRegistry) {
// Enable a simple memory-based message broker to send messages to clients
// Prefix for messages FROM server TO client
registry.enableSimpleBroker(CHANNEL_REFEREE_NAME)
// Prefix for messages FROM client TO server
registry.setApplicationDestinationPrefixes("/ws")
}
override fun registerStompEndpoints(registry: StompEndpointRegistry) {
// Register the "/ws" endpoint, enabling SockJS fallback options
registry.addEndpoint("/ws/referees-app")
.setAllowedOriginPatterns("*") // Allow connections from any origin (adjust for production)
.withSockJS()
}
}

View file

@ -15,7 +15,7 @@ data class MatchBean(
@Id @Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "match_sequence") @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "match_sequence")
@SequenceGenerator(name = "match_sequence", sequenceName = "match_seq", allocationSize = 1) @SequenceGenerator(name = "match_sequence", sequenceName = "match_seq", allocationSize = 1)
val id:Long?=null, var id:Long?=null,
val weapon:String?=null, val weapon:String?=null,
val country:String?=null, val country:String?=null,
val city:String?=null, val city:String?=null,

View file

@ -0,0 +1,3 @@
package fr.teamflash.fencerjudgeback.entities
data class MatchUpdateBean(val match: MatchBean?=null, val playerId:Long?=null)

View file

@ -1,7 +1,8 @@
package fr.teamflash.fencerjudgeback.websocket.controllers package fr.teamflash.fencerjudgeback.websocket.controllers
import fr.teamflash.fencerjudgeback.config.CHANNEL_NAME import fr.teamflash.fencerjudgeback.config.CHANNEL_MATCH_NAME
import fr.teamflash.fencerjudgeback.entities.MatchBean import fr.teamflash.fencerjudgeback.entities.MatchBean
import fr.teamflash.fencerjudgeback.entities.MatchUpdateBean
import fr.teamflash.fencerjudgeback.services.MatchService import fr.teamflash.fencerjudgeback.services.MatchService
import fr.teamflash.fencerjudgeback.websocket.models.MatchUpdateMessage import fr.teamflash.fencerjudgeback.websocket.models.MatchUpdateMessage
import org.springframework.context.event.EventListener import org.springframework.context.event.EventListener
@ -9,16 +10,15 @@ import org.springframework.messaging.handler.annotation.MessageMapping
import org.springframework.messaging.simp.SimpMessagingTemplate import org.springframework.messaging.simp.SimpMessagingTemplate
import org.springframework.messaging.simp.stomp.StompHeaderAccessor import org.springframework.messaging.simp.stomp.StompHeaderAccessor
import org.springframework.stereotype.Controller import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.socket.messaging.SessionSubscribeEvent import org.springframework.web.socket.messaging.SessionSubscribeEvent
@Controller @Controller
@RequestMapping("/ws/matches")
class MatchWebSocketController( class MatchWebSocketController(
private val matchService: MatchService, private val matchService: MatchService,
private val messagingTemplate: SimpMessagingTemplate private val messagingTemplate: SimpMessagingTemplate
) { ) {
private var mainId:Long? = 1
private val messageHistory = ArrayList<MatchBean>() private val messageHistory = ArrayList<MatchBean>()
@MessageMapping("/all") @MessageMapping("/all")
@ -28,7 +28,7 @@ class MatchWebSocketController(
// Envoyer la liste des messages sur le channel // Envoyer la liste des messages sur le channel
//Si la variable est dans le même package il faut enlever WebSocketConfig. //Si la variable est dans le même package il faut enlever WebSocketConfig.
messagingTemplate.convertAndSend(CHANNEL_NAME, messageHistory) messagingTemplate.convertAndSend(CHANNEL_MATCH_NAME, messageHistory)
} }
/** /**
@ -69,34 +69,50 @@ class MatchWebSocketController(
@EventListener @EventListener
fun handleWebSocketSubscribeListener(event: SessionSubscribeEvent) { fun handleWebSocketSubscribeListener(event: SessionSubscribeEvent) {
val headerAccessor = StompHeaderAccessor.wrap(event.message) val headerAccessor = StompHeaderAccessor.wrap(event.message)
if (CHANNEL_NAME == headerAccessor.destination) { if (CHANNEL_MATCH_NAME == headerAccessor.destination) {
messagingTemplate.convertAndSend(CHANNEL_NAME, messageHistory) messagingTemplate.convertAndSend(CHANNEL_MATCH_NAME, messageHistory)
println("Lancement...") println("Lancement du WebSocket")
} }
} }
fun addPoint(match:MatchBean, playerId:Long) { @MessageMapping("/plusPoint")
when (playerId) { fun addPoint(matchUpdateBean: MatchUpdateBean) {
match.player1ID -> match.score1 += 1 val playerId = matchUpdateBean.playerId
match.player2ID -> match.score2 += 1 val match = matchUpdateBean.match
print("plus")
if (match != null) {
print("minus")
when (playerId) {
match.player1ID -> if (match.score1 > 0) match.score1 -= 1
match.player2ID -> if (match.score2 > 0) match.score2 -= 1
}
matchService.updateMatch(match.id, match)
broadcastMatchUpdate(match)
} }
matchService.updateMatch(match.id, match)
broadcastMatchUpdate(match)
} }
fun minusPoint(match:MatchBean, playerId:Long) { @MessageMapping("/minusPoint")
when (playerId) { fun minusPoint(matchUpdateBean: MatchUpdateBean) {
match.player1ID -> if (match.score1 > 0) match.score1 -= 1 val playerId = matchUpdateBean.playerId
match.player2ID -> if (match.score2 > 0) match.score2 -= 1 val match = matchUpdateBean.match
print("minus")
if (match != null) {
when (playerId) {
match.player1ID -> if (match.score1 > 0) match.score1 -= 1
match.player2ID -> if (match.score2 > 0) match.score2 -= 1
}
matchService.updateMatch(match.id, match)
broadcastMatchUpdate(match)
}
} }
matchService.updateMatch(match.id, match)
broadcastMatchUpdate(match)
}
@MessageMapping("/add") @MessageMapping("/add")
fun addMatchtoMainList(match:MatchBean) { fun addMatchtoMainList(match:MatchBean) {
match.id = mainId;
matchService.addMatch(match) matchService.addMatch(match)
messageHistory.add(match) messageHistory.add(match)
broadcastMatchUpdate(match, MatchUpdateMessage.UpdateType.NEW_MATCH) broadcastMatchUpdate(match, MatchUpdateMessage.UpdateType.NEW_MATCH)
mainId = mainId?.plus(1)
println("Ajout du match $match.id en bdd")
} }
} }

View file

@ -1,6 +1,6 @@
package fr.teamflash.fencerjudgeback.websocket.controllers package fr.teamflash.fencerjudgeback.websocket.controllers
import fr.teamflash.fencerjudgeback.config.CHANNEL_NAME import fr.teamflash.fencerjudgeback.config.CHANNEL_MATCH_NAME
import fr.teamflash.fencerjudgeback.entities.RefereeBean import fr.teamflash.fencerjudgeback.entities.RefereeBean
import fr.teamflash.fencerjudgeback.services.RefereeService import fr.teamflash.fencerjudgeback.services.RefereeService
import fr.teamflash.fencerjudgeback.websocket.models.RefereeUpdateMessage import fr.teamflash.fencerjudgeback.websocket.models.RefereeUpdateMessage

View file

@ -0,0 +1,88 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Test WebSocket Match</title>
<style>
#messageArea {
width: 100%;
height: 300px;
border: 1px solid #ddd;
overflow-y: auto;
padding: 10px;
margin-bottom: 10px;
font-family: monospace;
}
input, button {
padding: 8px;
margin: 4px;
}
.input-group {
margin-bottom: 10px;
}
</style>
</head>
<body>
<h2>Test WebSocket Match</h2>
<div id="messageArea">Connexion...</div>
<div class="input-group">
<input type="number" id="player1Id" placeholder="Joueur 1 ID" value="2">
<input type="number" id="player2Id" placeholder="Joueur 2 ID" value="2">
<input type="number" id="refereeId" placeholder="Arbitre ID" value="2">
</div>
<div class="input-group">
<input type="number" id="score1" placeholder="Score Joueur 1" value="2">
<input type="number" id="score2" placeholder="Score Joueur 2" value="14">
<input type="datetime-local" id="matchDate">
</div>
<button onclick="sendMatch()">Envoyer Match</button>
<script src="https://cdn.jsdelivr.net/npm/sockjs-client/dist/sockjs.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>
<script>
const stompClient = Stomp.over(new SockJS('/ws/matches-app'));
const channel = "/ws/topic/match";
stompClient.connect({}, function () {
stompClient.subscribe(channel, function (message) {
const msg = JSON.parse(message.body);
console.log("Match reçu :", msg);
displayMessage(msg);
});
document.getElementById('messageArea').textContent = 'Connecté au WebSocket';
}, function (error) {
document.getElementById('messageArea').textContent = 'Erreur WebSocket : ' + error;
});
function sendMatch() {
const match = {
id: 1,
player1Id: parseInt(document.getElementById("player1Id").value),
player2Id: parseInt(document.getElementById("player2Id").value),
refereeId: parseInt(document.getElementById("refereeId").value),
score1: parseInt(document.getElementById("score1").value),
score2: parseInt(document.getElementById("score2").value),
date: document.getElementById("matchDate").value
};
stompClient.send("/ws/matches/add", {}, JSON.stringify(match));
displayMessage(match)
}
function displayMessage(match) {
const area = document.getElementById("messageArea");
const div = document.createElement("div");
div.textContent = `Match ${match.id}: ${match.player1Id} (${match.score1}) vs ${match.player2Id} (${match.score2})`;
area.appendChild(div);
}
</script>
</body>
</html>

View file

@ -47,8 +47,8 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>
<script> <script>
const stompClient = Stomp.over(new SockJS('/ws/matches-app')); const stompClient = Stomp.over(new SockJS('/ws/players-app'));
const channel = "/ws/topic"; const channel = "/ws/topic/player";
stompClient.connect({}, function () { stompClient.connect({}, function () {
stompClient.subscribe(channel, function (message) { stompClient.subscribe(channel, function (message) {

View file

@ -0,0 +1,91 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Test WebSocket Match</title>
<style>
#messageArea {
width: 100%;
height: 300px;
border: 1px solid #ddd;
overflow-y: auto;
padding: 10px;
margin-bottom: 10px;
font-family: monospace;
}
input, button {
padding: 8px;
margin: 4px;
}
.input-group {
margin-bottom: 10px;
}
</style>
</head>
<body>
<h2>Test WebSocket Match</h2>
<div id="messageArea">Connexion...</div>
<div class="input-group">
<input type="number" id="player1Id" placeholder="Joueur 1 ID" value="2">
<input type="number" id="player2Id" placeholder="Joueur 2 ID" value="2">
<input type="number" id="refereeId" placeholder="Arbitre ID" value="2">
</div>
<div class="input-group">
<input type="number" id="score1" placeholder="Score Joueur 1" value="2">
<input type="number" id="score2" placeholder="Score Joueur 2" value="14">
<input type="datetime-local" id="matchDate">
</div>
<button onclick="sendMatch()">Envoyer Match</button>
<script src="https://cdn.jsdelivr.net/npm/sockjs-client/dist/sockjs.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>
<script>
const stompClient = Stomp.over(new SockJS('/ws/matches-app'));
const channel = "/ws/topic/match";
stompClient.connect({}, function () {
stompClient.subscribe(channel, function (message) {
const msg = JSON.parse(message.body);
console.log("Match reçu :", msg);
displayMessage(msg);
});
document.getElementById('messageArea').textContent = 'Connecté au WebSocket';
}, function (error) {
document.getElementById('messageArea').textContent = 'Erreur WebSocket : ' + error;
});
function sendMatch() {
const match = {
id: 1,
player1Id: parseInt(document.getElementById("player1Id").value),
player2Id: parseInt(document.getElementById("player2Id").value),
refereeId: parseInt(document.getElementById("refereeId").value),
score1: parseInt(document.getElementById("score1").value),
score2: parseInt(document.getElementById("score2").value),
date: document.getElementById("matchDate").value
};
stompClient.send("/ws/matches/addPoint", {}, JSON.stringify({
match: match,
playerId: match.player1Id
}));
displayMessage(match)
}
function displayMessage(match) {
const area = document.getElementById("messageArea");
const div = document.createElement("div");
div.textContent = `Match ${match.id}: ${match.player1Id} (${match.score1}) vs ${match.player2Id} (${match.score2})`;
area.appendChild(div);
}
</script>
</body>
</html>