Erweiterungen
This commit is contained in:
@@ -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"]
|
||||||
|
|||||||
@@ -214,4 +214,89 @@ Zum Testen der STOMP-Funktionalität können Sie:
|
|||||||
2. Browser-Entwicklertools für WebSocket-Verbindungen nutzen
|
2. Browser-Entwicklertools für WebSocket-Verbindungen nutzen
|
||||||
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.
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -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.
|
||||||
|
|||||||
Reference in New Issue
Block a user