Erweiterungen
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
FROM eclipse-temurin:21-jre
|
||||
COPY target/*.jar app.jar
|
||||
EXPOSE 8080
|
||||
ENTRYPOINT ["java", "-jar", "/app.jar"]
|
||||
ENTRYPOINT ["java", "-jar", "/app.jar", "--spring.profiles.active=production"]
|
||||
|
||||
@@ -214,4 +214,89 @@ Zum Testen der STOMP-Funktionalität können Sie:
|
||||
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.
|
||||
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.
@@ -206,4 +206,71 @@ public class MessageController {
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.Field;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@@ -26,6 +28,19 @@ public class TaskEntry {
|
||||
@Field("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.
|
||||
* This ensures that the task id is returned as a string when jobs are retrieved via API.
|
||||
|
||||
Reference in New Issue
Block a user