Erweiterungen
This commit is contained in:
130
STOMP_README.md
Normal file
130
STOMP_README.md
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
# STOMP Messaging Integration
|
||||||
|
|
||||||
|
Die Anwendung unterstützt jetzt STOMP (Simple Text Oriented Messaging Protocol) für die Kommunikation mit externen Apps über WebSocket-Verbindungen.
|
||||||
|
|
||||||
|
## Übersicht
|
||||||
|
|
||||||
|
Das System bietet folgende STOMP-Funktionalitäten:
|
||||||
|
|
||||||
|
### WebSocket-Endpunkte
|
||||||
|
|
||||||
|
- **`/ws`** - STOMP-Endpunkt mit SockJS-Fallback-Unterstützung
|
||||||
|
- **`/websocket`** - Reiner WebSocket-Endpunkt ohne SockJS
|
||||||
|
|
||||||
|
### Nachrichtendestinationen
|
||||||
|
|
||||||
|
#### Eingehende Nachrichten (Client → Server)
|
||||||
|
- **`/app/message`** - Allgemeine Nachrichten
|
||||||
|
- **`/app/job/status`** - Job-Status-Updates
|
||||||
|
- **`/app/device/location`** - Gerätestandort-Updates
|
||||||
|
|
||||||
|
#### Ausgehende Nachrichten (Server → Client)
|
||||||
|
- **`/topic/messages`** - Broadcast aller allgemeinen Nachrichten
|
||||||
|
- **`/topic/job-updates`** - Job-Status-Updates für alle Abonnenten
|
||||||
|
- **`/topic/device-locations`** - Gerätestandort-Updates
|
||||||
|
- **`/topic/broadcasts`** - System-weite Broadcast-Nachrichten
|
||||||
|
- **`/queue/notifications`** - Benutzerspezifische Benachrichtigungen
|
||||||
|
|
||||||
|
## Verwendung für Apps
|
||||||
|
|
||||||
|
### 1. Verbindung aufbauen
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Mit SockJS
|
||||||
|
const socket = new SockJS('http://localhost:8080/ws');
|
||||||
|
const stompClient = Stomp.over(socket);
|
||||||
|
|
||||||
|
// Oder mit nativem WebSocket
|
||||||
|
const socket = new WebSocket('ws://localhost:8080/websocket');
|
||||||
|
const stompClient = Stomp.over(socket);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Verbindung herstellen
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
stompClient.connect({}, function(frame) {
|
||||||
|
console.log('Verbunden: ' + frame);
|
||||||
|
|
||||||
|
// Nachrichten abonnieren
|
||||||
|
stompClient.subscribe('/topic/messages', function(message) {
|
||||||
|
console.log('Nachricht erhalten:', JSON.parse(message.body));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Nachrichten senden
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Allgemeine Nachricht senden
|
||||||
|
stompClient.send('/app/message', {}, JSON.stringify({
|
||||||
|
content: 'Hallo vom App',
|
||||||
|
sender: 'MobileApp'
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Job-Status-Update senden
|
||||||
|
stompClient.send('/app/job/status', {}, JSON.stringify({
|
||||||
|
jobId: '12345',
|
||||||
|
status: 'IN_PROGRESS',
|
||||||
|
progress: 75
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Gerätestandort senden
|
||||||
|
stompClient.send('/app/device/location', {}, JSON.stringify({
|
||||||
|
deviceId: 'device-001',
|
||||||
|
latitude: 52.5200,
|
||||||
|
longitude: 13.4050,
|
||||||
|
accuracy: 10
|
||||||
|
}));
|
||||||
|
```
|
||||||
|
|
||||||
|
## Backend-Integration
|
||||||
|
|
||||||
|
### Programmatische Nachrichten senden
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Autowired
|
||||||
|
private MessageController messageController;
|
||||||
|
|
||||||
|
// Benachrichtigung an spezifischen Benutzer
|
||||||
|
messageController.sendNotificationToUser("username", "Neue Aufgabe verfügbar");
|
||||||
|
|
||||||
|
// Broadcast-Nachricht an alle
|
||||||
|
messageController.sendBroadcastMessage("Systemwartung in 10 Minuten");
|
||||||
|
```
|
||||||
|
|
||||||
|
## Konfiguration
|
||||||
|
|
||||||
|
Die STOMP-Konfiguration befindet sich in:
|
||||||
|
- **`WebSocketConfig.java`** - WebSocket und STOMP-Konfiguration
|
||||||
|
- **`MessageController.java`** - Nachrichtenbehandlung
|
||||||
|
- **`application.properties`** - Zusätzliche WebSocket-Einstellungen
|
||||||
|
|
||||||
|
### Wichtige Konfigurationsparameter
|
||||||
|
|
||||||
|
```properties
|
||||||
|
# Nachrichtenpuffergröße
|
||||||
|
spring.websocket.servlet.max-text-message-buffer-size=8192
|
||||||
|
spring.websocket.servlet.max-binary-message-buffer-size=8192
|
||||||
|
|
||||||
|
# STOMP aktivieren
|
||||||
|
spring.websocket.stomp.enabled=true
|
||||||
|
|
||||||
|
# Heartbeat-Einstellungen
|
||||||
|
spring.websocket.stomp.heartbeat.outgoing=10000
|
||||||
|
spring.websocket.stomp.heartbeat.incoming=10000
|
||||||
|
```
|
||||||
|
|
||||||
|
## Sicherheitshinweise
|
||||||
|
|
||||||
|
- WebSocket-Verbindungen verwenden die gleiche Authentifizierung wie die Web-Anwendung
|
||||||
|
- Nachrichten werden automatisch mit Zeitstempel versehen
|
||||||
|
- Alle Nachrichten werden in JSON-Format verarbeitet
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
Zum Testen der STOMP-Funktionalität können Sie:
|
||||||
|
1. Eine WebSocket-Client-Bibliothek verwenden
|
||||||
|
2. Browser-Entwicklertools für WebSocket-Verbindungen nutzen
|
||||||
|
3. Spezialisierte STOMP-Testing-Tools einsetzen
|
||||||
|
|
||||||
|
Die Implementierung ist vollständig und bereit für die Integration mit externen Apps.
|
||||||
10
pom.xml
10
pom.xml
@@ -93,6 +93,16 @@
|
|||||||
<version>2.0.1</version>
|
<version>2.0.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- WebSocket and STOMP Dependencies for messaging -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-messaging</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
36
src/main/java/de/assecutor/votianlt/config/MailConfig.java
Normal file
36
src/main/java/de/assecutor/votianlt/config/MailConfig.java
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package de.assecutor.votianlt.config;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class MailConfig {
|
||||||
|
|
||||||
|
@Value("${mail.smtp.username}")
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@Value("${mail.smtp.password}")
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
@Value("${mail.smtp.host:smtp.gmail.com}")
|
||||||
|
private String host;
|
||||||
|
|
||||||
|
@Value("${mail.smtp.port:587}")
|
||||||
|
private int port;
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHost() {
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPort() {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package de.assecutor.votianlt.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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WebSocket configuration for STOMP messaging.
|
||||||
|
* Enables real-time communication with client applications.
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSocketMessageBroker
|
||||||
|
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configureMessageBroker(MessageBrokerRegistry config) {
|
||||||
|
// Enable a simple memory-based message broker to carry messages back to client
|
||||||
|
// on destinations prefixed with "/topic" and "/queue"
|
||||||
|
config.enableSimpleBroker("/topic", "/queue");
|
||||||
|
|
||||||
|
// Designate the "/app" prefix for messages that are bound to methods
|
||||||
|
// annotated with @MessageMapping
|
||||||
|
config.setApplicationDestinationPrefixes("/app");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||||
|
// Register the "/ws" endpoint for WebSocket connections
|
||||||
|
// withSockJS() enables SockJS fallback options for browsers that don't support WebSocket
|
||||||
|
registry.addEndpoint("/ws").withSockJS();
|
||||||
|
|
||||||
|
// Also add a plain WebSocket endpoint without SockJS for native WebSocket clients
|
||||||
|
registry.addEndpoint("/websocket");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package de.assecutor.votianlt.controller;
|
||||||
|
|
||||||
|
import org.springframework.messaging.handler.annotation.MessageMapping;
|
||||||
|
import org.springframework.messaging.handler.annotation.SendTo;
|
||||||
|
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* STOMP message controller for handling real-time communication with apps.
|
||||||
|
* Provides endpoints for sending and receiving messages via WebSocket/STOMP.
|
||||||
|
*/
|
||||||
|
@Controller
|
||||||
|
public class MessageController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SimpMessagingTemplate messagingTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles messages sent to /app/message and broadcasts them to all subscribers of /topic/messages
|
||||||
|
*/
|
||||||
|
@MessageMapping("/message")
|
||||||
|
@SendTo("/topic/messages")
|
||||||
|
public Map<String, Object> handleMessage(Map<String, Object> message) {
|
||||||
|
// Add timestamp to the message
|
||||||
|
message.put("timestamp", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
|
||||||
|
message.put("processed", true);
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles job status updates from apps
|
||||||
|
*/
|
||||||
|
@MessageMapping("/job/status")
|
||||||
|
@SendTo("/topic/job-updates")
|
||||||
|
public Map<String, Object> handleJobStatusUpdate(Map<String, Object> jobUpdate) {
|
||||||
|
jobUpdate.put("timestamp", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
|
||||||
|
jobUpdate.put("source", "app");
|
||||||
|
|
||||||
|
return jobUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles device location updates from mobile apps
|
||||||
|
*/
|
||||||
|
@MessageMapping("/device/location")
|
||||||
|
@SendTo("/topic/device-locations")
|
||||||
|
public Map<String, Object> handleDeviceLocation(Map<String, Object> locationUpdate) {
|
||||||
|
locationUpdate.put("timestamp", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
|
||||||
|
locationUpdate.put("processed", true);
|
||||||
|
|
||||||
|
return locationUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send notification to specific user
|
||||||
|
*/
|
||||||
|
public void sendNotificationToUser(String username, String message) {
|
||||||
|
Map<String, Object> notification = Map.of(
|
||||||
|
"message", message,
|
||||||
|
"timestamp", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME),
|
||||||
|
"type", "notification"
|
||||||
|
);
|
||||||
|
|
||||||
|
messagingTemplate.convertAndSendToUser(username, "/queue/notifications", notification);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send broadcast message to all connected clients
|
||||||
|
*/
|
||||||
|
public void sendBroadcastMessage(String message) {
|
||||||
|
Map<String, Object> broadcast = Map.of(
|
||||||
|
"message", message,
|
||||||
|
"timestamp", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME),
|
||||||
|
"type", "broadcast"
|
||||||
|
);
|
||||||
|
|
||||||
|
messagingTemplate.convertAndSend("/topic/broadcasts", broadcast);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package de.assecutor.votianlt.util;
|
package de.assecutor.votianlt.util;
|
||||||
|
|
||||||
|
import de.assecutor.votianlt.config.MailConfig;
|
||||||
import jakarta.mail.Message;
|
import jakarta.mail.Message;
|
||||||
import jakarta.mail.MessagingException;
|
import jakarta.mail.MessagingException;
|
||||||
import jakarta.mail.PasswordAuthentication;
|
import jakarta.mail.PasswordAuthentication;
|
||||||
@@ -7,15 +8,26 @@ import jakarta.mail.Session;
|
|||||||
import jakarta.mail.Transport;
|
import jakarta.mail.Transport;
|
||||||
import jakarta.mail.internet.InternetAddress;
|
import jakarta.mail.internet.InternetAddress;
|
||||||
import jakarta.mail.internet.MimeMessage;
|
import jakarta.mail.internet.MimeMessage;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
|
@Component
|
||||||
public class MailUtil {
|
public class MailUtil {
|
||||||
public static void sendMail(String to, String subject, String body) throws MessagingException {
|
|
||||||
// SMTP-Konfiguration (hier Beispiel für Gmail, anpassen für Produktivsystem!)
|
private final MailConfig mailConfig;
|
||||||
final String username = "your-email@gmail.com"; // TODO: ersetzen
|
|
||||||
final String password = "your-password"; // TODO: ersetzen
|
@Autowired
|
||||||
final String host = "smtp.gmail.com";
|
public MailUtil(MailConfig mailConfig) {
|
||||||
final int port = 587;
|
this.mailConfig = mailConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendMail(String to, String subject, String body) throws MessagingException {
|
||||||
|
// SMTP-Konfiguration aus externalisierter Konfiguration
|
||||||
|
final String username = mailConfig.getUsername();
|
||||||
|
final String password = mailConfig.getPassword();
|
||||||
|
final String host = mailConfig.getHost();
|
||||||
|
final int port = mailConfig.getPort();
|
||||||
|
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
props.put("mail.smtp.auth", "true");
|
props.put("mail.smtp.auth", "true");
|
||||||
|
|||||||
@@ -13,3 +13,19 @@ spring.jpa.open-in-view=false
|
|||||||
|
|
||||||
# MongoDB
|
# MongoDB
|
||||||
spring.data.mongodb.uri=mongodb://192.168.180.25:27017/votianlt
|
spring.data.mongodb.uri=mongodb://192.168.180.25:27017/votianlt
|
||||||
|
|
||||||
|
# Mail Configuration
|
||||||
|
mail.smtp.username=your-email@gmail.com
|
||||||
|
mail.smtp.password=your-password
|
||||||
|
mail.smtp.host=smtp.gmail.com
|
||||||
|
mail.smtp.port=587
|
||||||
|
|
||||||
|
# WebSocket and STOMP Configuration
|
||||||
|
# WebSocket message size limits (in bytes)
|
||||||
|
spring.websocket.servlet.max-text-message-buffer-size=8192
|
||||||
|
spring.websocket.servlet.max-binary-message-buffer-size=8192
|
||||||
|
# Enable STOMP over WebSocket
|
||||||
|
spring.websocket.stomp.enabled=true
|
||||||
|
# STOMP heartbeat settings (in milliseconds)
|
||||||
|
spring.websocket.stomp.heartbeat.outgoing=10000
|
||||||
|
spring.websocket.stomp.heartbeat.incoming=10000
|
||||||
Reference in New Issue
Block a user