Erweiterungen

This commit is contained in:
2025-09-05 23:15:56 +02:00
parent f444f50538
commit 9b0cc32605
5 changed files with 169 additions and 2 deletions

View File

@@ -1,4 +1,4 @@
FROM eclipse-temurin:21-jre FROM eclipse-temurin:21-jre
COPY target/*.jar app.jar COPY target/*.jar app.jar
EXPOSE 8080 EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app.jar"] ENTRYPOINT ["java", "-jar", "/app.jar", "--spring.profiles.active=production"]

View File

@@ -215,3 +215,88 @@ Zum Testen der STOMP-Funktionalität können Sie:
3. Spezialisierte STOMP-Testing-Tools einsetzen 3. Spezialisierte STOMP-Testing-Tools einsetzen
Die Implementierung ist vollständig und bereit für die Integration mit externen Apps. Die Implementierung ist vollständig und bereit für die Integration mit externen Apps.
## Neue STOMP-Schnittstelle: Task-Erledigung melden
Mit dieser Schnittstelle kann ein Client die Erledigung eines Tasks melden.
- Senden (Client → Server): `/app/task/completed`
- Broadcasts (Server → Client):
- Global: `/topic/task-updates`
- Task-spezifisch: `/topic/tasks/{taskId}`
Payload (JSON):
```json
{
"taskId": "<MongoId als String>",
"completedBy": "<optional: Name/ID des Ausführenden>",
"note": "<optional: Kommentar>"
}
```
Antwort (Beispiel):
```json
{
"timestamp": "2025-09-05T09:25:00",
"type": "taskCompletedAck",
"success": true,
"taskId": "...",
"jobId": "...",
"completed": true,
"completedAt": "2025-09-05T09:25:00",
"completedBy": "driver01",
"note": "Übergabe erfolgreich",
"event": "taskCompleted"
}
```
JavaScript Beispiel:
```javascript
// Abonnieren der globalen Updates
stompClient.subscribe('/topic/task-updates', (frame) => {
console.log('Task update:', JSON.parse(frame.body));
});
// Abonnieren eines spezifischen Tasks
stompClient.subscribe('/topic/tasks/' + taskId, (frame) => {
console.log('Task-specific update:', JSON.parse(frame.body));
});
// Task als erledigt melden
stompClient.send('/app/task/completed', {}, JSON.stringify({
taskId: taskId,
completedBy: 'driver01',
note: 'Übergabe erfolgreich'
}));
```
Flutter/Dart Beispiel:
```dart
stompClient.subscribe(
destination: '/topic/task-updates',
callback: (frame) => print('Task update: ${frame.body}'),
);
stompClient.subscribe(
destination: '/topic/tasks/$taskId',
callback: (frame) => print('Task-specific update: ${frame.body}'),
);
stompClient.send(
destination: '/app/task/completed',
body: jsonEncode({
'taskId': taskId,
'completedBy': 'driver01',
'note': 'Übergabe erfolgreich',
}),
);
```
Hinweise:
- `taskId` ist Pflicht. Bei ungültiger oder unbekannter `taskId` wird `success=false` zurückgegeben.
- Der Server setzt `completed=true` und `completedAt` automatisch.
- Zusätzlich zum globalen Broadcast wird ein task-spezifisches Event auf `/topic/tasks/{taskId}` versendet.

Binary file not shown.

View File

@@ -206,4 +206,71 @@ public class MessageController {
return jobsWithRelatedData; return jobsWithRelatedData;
} }
/**
* Report task completion from apps.
* Client sends to /app/task/completed with payload { taskId, completedBy?, note? }.
* Broadcasts to /topic/task-updates and /topic/tasks/{taskId}.
*/
@MessageMapping("/task/completed")
@SendTo("/topic/task-updates")
public Map<String, Object> handleTaskCompleted(Map<String, Object> payload) {
log.info("STOMP Endpoint '/app/task/completed' called with data: {}", payload);
Map<String, Object> response = new java.util.HashMap<>();
response.put("timestamp", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
response.put("type", "taskCompletedAck");
if (payload == null || !payload.containsKey("taskId") || payload.get("taskId") == null || payload.get("taskId").toString().isBlank()) {
response.put("success", false);
response.put("message", "taskId ist erforderlich");
log.info("Task completion failed: {}", response);
return response;
}
String taskIdStr = payload.get("taskId").toString();
String completedBy = payload.get("completedBy") != null ? payload.get("completedBy").toString() : null;
String note = payload.get("note") != null ? payload.get("note").toString() : null;
try {
org.bson.types.ObjectId taskId = new org.bson.types.ObjectId(taskIdStr);
java.util.Optional<TaskEntry> opt = taskRepository.findById(taskId);
if (opt.isEmpty()) {
response.put("success", false);
response.put("message", "Task nicht gefunden");
return response;
}
TaskEntry task = opt.get();
task.setCompleted(true);
task.setCompletedAt(LocalDateTime.now());
if (completedBy != null) task.setCompletedBy(completedBy);
if (note != null) task.setCompletionNote(note);
taskRepository.save(task);
java.util.Map<String, Object> event = new java.util.HashMap<>();
event.put("taskId", task.getIdAsString());
event.put("jobId", task.getJobIdAsString());
event.put("completed", task.isCompleted());
event.put("completedAt", task.getCompletedAt() != null ? task.getCompletedAt().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) : null);
event.put("completedBy", task.getCompletedBy());
event.put("note", task.getCompletionNote());
event.put("event", "taskCompleted");
// Send specific task topic
messagingTemplate.convertAndSend("/topic/tasks/" + task.getIdAsString(), event);
response.put("success", true);
response.putAll(event);
log.info("Task completion processed successfully for taskId={}", taskIdStr);
return response;
} catch (IllegalArgumentException e) {
response.put("success", false);
response.put("message", "Ungültige taskId");
return response;
} catch (Exception e) {
log.error("Error processing task completion", e);
response.put("success", false);
response.put("message", "Fehler bei der Verarbeitung");
return response;
}
}
} }

View File

@@ -10,6 +10,8 @@ import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field; import org.springframework.data.mongodb.core.mapping.Field;
import java.time.LocalDateTime;
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@@ -26,6 +28,19 @@ public class TaskEntry {
@Field("text") @Field("text")
private String text; private String text;
// Completion tracking
@Field("completed")
private boolean completed = false;
@Field("completed_at")
private LocalDateTime completedAt;
@Field("completed_by")
private String completedBy;
@Field("completion_note")
private String completionNote;
/** /**
* Returns the ObjectId as string for JSON serialization. * Returns the ObjectId as string for JSON serialization.
* This ensures that the task id is returned as a string when jobs are retrieved via API. * This ensures that the task id is returned as a string when jobs are retrieved via API.