package com.sinata.appointment.service;
|
|
import com.sinata.appointment.constants.IntegrationConstant;
|
import com.sinata.appointment.dto.ExportTaskStatusVo;
|
import java.io.IOException;
|
import java.nio.file.Files;
|
import java.nio.file.Path;
|
import java.nio.file.Paths;
|
import java.time.LocalDate;
|
import java.time.format.DateTimeParseException;
|
import java.util.HashMap;
|
import java.util.Map;
|
import java.util.UUID;
|
import java.util.concurrent.ConcurrentHashMap;
|
import lombok.RequiredArgsConstructor;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.stereotype.Service;
|
|
@Slf4j
|
@Service
|
@RequiredArgsConstructor
|
public class ExportApplicationService {
|
|
private static final String STATUS_QUEUED = "QUEUED";
|
private static final String STATUS_RUNNING = "RUNNING";
|
private static final String STATUS_COMPLETED = "COMPLETED";
|
private static final String STATUS_FAILED = "FAILED";
|
private static final String APPOINTMENT_EXPORT_TYPE = "appointment";
|
|
private final ObjectProvider<RabbitTemplate> rabbitTemplateProvider;
|
private final AppointmentApplicationService appointmentApplicationService;
|
private final LocalExportAsyncService localExportAsyncService;
|
|
private final ConcurrentHashMap<String, ExportTaskSnapshot> taskStore = new ConcurrentHashMap<>();
|
|
public String enqueueExport(String exportType, Map<String, Object> criteria) {
|
String normalizedType = normalizeType(exportType);
|
String taskId = UUID.randomUUID().toString().replace("-", "");
|
Map<String, Object> safeCriteria = criteria == null ? Map.of() : new HashMap<>(criteria);
|
RabbitTemplate rabbitTemplate = rabbitTemplateProvider.getIfAvailable();
|
if (rabbitTemplate == null) {
|
taskStore.put(taskId, ExportTaskSnapshot.queued(taskId, normalizedType));
|
localExportAsyncService.process(taskId, normalizedType, safeCriteria);
|
return taskId;
|
}
|
taskStore.put(taskId, ExportTaskSnapshot.queued(taskId, normalizedType));
|
log.info("Enqueue export taskId={} type={}", taskId, normalizedType);
|
Map<String, Object> payload = new HashMap<>();
|
payload.put("taskId", taskId);
|
payload.put("type", normalizedType);
|
payload.put("criteria", safeCriteria);
|
rabbitTemplate.convertAndSend(IntegrationConstant.EXPORT_TASK_QUEUE, payload);
|
return taskId;
|
}
|
|
public ExportTaskStatusVo getTaskStatus(String taskId) {
|
ExportTaskSnapshot snapshot = taskStore.get(taskId);
|
if (snapshot == null) {
|
return null;
|
}
|
ExportTaskStatusVo vo = new ExportTaskStatusVo();
|
vo.setTaskId(snapshot.taskId());
|
vo.setType(snapshot.type());
|
vo.setStatus(snapshot.status());
|
vo.setFileName(snapshot.fileName());
|
vo.setErrorMessage(snapshot.errorMessage());
|
return vo;
|
}
|
|
public Path getExportFilePath(String taskId) {
|
ExportTaskSnapshot snapshot = taskStore.get(taskId);
|
if (snapshot == null || snapshot.filePath() == null || !Files.exists(snapshot.filePath())) {
|
return null;
|
}
|
return snapshot.filePath();
|
}
|
|
void processLocalExport(String taskId, String exportType, Map<String, Object> criteria) {
|
taskStore.computeIfPresent(taskId, (_k, v) -> v.toRunning());
|
try {
|
if (!APPOINTMENT_EXPORT_TYPE.equals(normalizeType(exportType))) {
|
throw new IllegalArgumentException("unsupported export type: " + exportType);
|
}
|
byte[] bytes =
|
appointmentApplicationService.exportExcel(
|
asString(criteria.get("visitedUserName")),
|
asLong(criteria.get("visitedDeptId")),
|
asString(criteria.get("accessArea")),
|
asString(criteria.get("localUnit")),
|
asLocalDate(criteria.get("visitDateStart")),
|
asLocalDate(criteria.get("visitDateEnd")),
|
asString(criteria.get("displayStatus")),
|
asString(criteria.get("approvalStatus")),
|
asString(criteria.get("visitorKeyword")),
|
asString(criteria.get("visitReasonCode")));
|
Path exportDir = Paths.get(System.getProperty("java.io.tmpdir"), "reservation-mini-program-exports");
|
Files.createDirectories(exportDir);
|
Path filePath = exportDir.resolve(taskId + ".xlsx");
|
Files.write(filePath, bytes);
|
taskStore.put(
|
taskId,
|
new ExportTaskSnapshot(taskId, normalizeType(exportType), STATUS_COMPLETED, filePath, filePath.getFileName().toString(), null));
|
} catch (Exception ex) {
|
log.error("Local export failed taskId={} type={}", taskId, exportType, ex);
|
taskStore.put(
|
taskId,
|
new ExportTaskSnapshot(taskId, normalizeType(exportType), STATUS_FAILED, null, null, ex.getMessage()));
|
}
|
}
|
|
private String normalizeType(String exportType) {
|
return exportType == null || exportType.isBlank() ? APPOINTMENT_EXPORT_TYPE : exportType.trim();
|
}
|
|
private String asString(Object value) {
|
return value == null ? null : value.toString().trim();
|
}
|
|
private Long asLong(Object value) {
|
if (value == null) {
|
return null;
|
}
|
try {
|
return Long.parseLong(value.toString().trim());
|
} catch (NumberFormatException ex) {
|
return null;
|
}
|
}
|
|
private LocalDate asLocalDate(Object value) {
|
if (value == null) {
|
return null;
|
}
|
try {
|
return LocalDate.parse(value.toString().trim());
|
} catch (DateTimeParseException ex) {
|
return null;
|
}
|
}
|
|
private record ExportTaskSnapshot(
|
String taskId,
|
String type,
|
String status,
|
Path filePath,
|
String fileName,
|
String errorMessage) {
|
|
private static ExportTaskSnapshot queued(String taskId, String type) {
|
return new ExportTaskSnapshot(taskId, type, STATUS_QUEUED, null, null, null);
|
}
|
|
private ExportTaskSnapshot toRunning() {
|
return new ExportTaskSnapshot(taskId, type, STATUS_RUNNING, filePath, fileName, errorMessage);
|
}
|
}
|
}
|