fix: store content type at upload time instead of guessing from extension
Previously FileService fell back to extension-based MIME detection, causing TIFF, HEIC, DOCX and other unlisted types to be served as octet-stream (forced download instead of inline display). - Add content_type column to documents (V3 migration) - Store file.getContentType() in DocumentService on upload and file replace - MassImportService uses Files.probeContentType() for local files - DocumentController prefers doc.getContentType() over S3-reported type - FileService: remove extension-based fallback (no longer needed) - DocumentService: replace leftover ResponseStatusException with DomainException Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -57,8 +57,13 @@ public class DocumentController {
|
||||
try {
|
||||
FileService.S3FileDownload download = fileService.downloadFile(doc.getFilePath());
|
||||
|
||||
// Prefer the content type stored at upload time; fall back to whatever S3 reports
|
||||
String contentType = (doc.getContentType() != null && !doc.getContentType().isBlank())
|
||||
? doc.getContentType()
|
||||
: download.contentType();
|
||||
|
||||
return ResponseEntity.ok()
|
||||
.contentType(MediaType.parseMediaType(download.contentType()))
|
||||
.contentType(MediaType.parseMediaType(contentType))
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"" + doc.getOriginalFilename() + "\"")
|
||||
.body(download.resource());
|
||||
} catch (FileService.StorageFileNotFoundException e) {
|
||||
|
||||
@@ -32,6 +32,10 @@ public class Document {
|
||||
@Column(name = "file_path")
|
||||
private String filePath;
|
||||
|
||||
// MIME-Type, gespeichert beim Upload (z.B. "application/pdf", "image/jpeg")
|
||||
@Column(name = "content_type")
|
||||
private String contentType;
|
||||
|
||||
// Originaler Dateiname beim Upload (z.B. "Brief_Oma_1940.pdf")
|
||||
@Column(name = "original_filename", nullable = false)
|
||||
private String originalFilename;
|
||||
|
||||
@@ -13,11 +13,11 @@ import org.raddatz.familienarchiv.repository.PersonRepository;
|
||||
import org.raddatz.familienarchiv.repository.TagRepository;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.raddatz.familienarchiv.exception.DomainException;
|
||||
import org.raddatz.familienarchiv.exception.ErrorCode;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
@@ -69,6 +69,7 @@ public class DocumentService {
|
||||
|
||||
// 3. Update Database
|
||||
document.setFilePath(s3Key);
|
||||
document.setContentType(file.getContentType());
|
||||
if (document.getStatus() == DocumentStatus.PLACEHOLDER) {
|
||||
document.setStatus(DocumentStatus.UPLOADED);
|
||||
}
|
||||
@@ -79,7 +80,7 @@ public class DocumentService {
|
||||
@Transactional
|
||||
public Document updateDocument(UUID id, DocumentUpdateDTO dto, MultipartFile newFile) throws IOException {
|
||||
Document doc = documentRepository.findById(id)
|
||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Dokument nicht gefunden"));
|
||||
.orElseThrow(() -> DomainException.notFound(ErrorCode.DOCUMENT_NOT_FOUND, "Document not found: " + id));
|
||||
|
||||
// 1. Einfache Felder Update
|
||||
doc.setTitle(dto.getTitle());
|
||||
@@ -125,6 +126,7 @@ public class DocumentService {
|
||||
|
||||
doc.setFilePath(s3Key);
|
||||
doc.setOriginalFilename(newFile.getOriginalFilename());
|
||||
doc.setContentType(newFile.getContentType());
|
||||
doc.setStatus(DocumentStatus.UPLOADED);
|
||||
}
|
||||
|
||||
|
||||
@@ -66,21 +66,10 @@ public class FileService {
|
||||
|
||||
ResponseInputStream<GetObjectResponse> s3Object = s3Client.getObject(getObjectRequest);
|
||||
|
||||
// 1. Versuche Content-Type von S3 zu bekommen
|
||||
// Use whatever content type S3 has stored (set at upload time)
|
||||
String contentType = s3Object.response().contentType();
|
||||
|
||||
// 2. FIX: Wenn S3 "octet-stream" sagt (oder null ist), raten wir anhand der Endung
|
||||
if (contentType == null || contentType.isEmpty() || contentType.equals("application/octet-stream")) {
|
||||
String keyLower = s3Key.toLowerCase();
|
||||
if (keyLower.endsWith(".pdf")) {
|
||||
contentType = "application/pdf";
|
||||
} else if (keyLower.endsWith(".jpg") || keyLower.endsWith(".jpeg")) {
|
||||
contentType = "image/jpeg";
|
||||
} else if (keyLower.endsWith(".png")) {
|
||||
contentType = "image/png";
|
||||
} else {
|
||||
contentType = "application/octet-stream"; // Fallback
|
||||
}
|
||||
if (contentType == null || contentType.isBlank()) {
|
||||
contentType = "application/octet-stream";
|
||||
}
|
||||
|
||||
return new S3FileDownload(new InputStreamResource(s3Object), contentType);
|
||||
|
||||
@@ -140,12 +140,22 @@ public class MassImportService {
|
||||
return;
|
||||
}
|
||||
|
||||
// Detect MIME type from the local file
|
||||
String contentType;
|
||||
try {
|
||||
contentType = Files.probeContentType(file.toPath());
|
||||
} catch (IOException e) {
|
||||
contentType = null;
|
||||
}
|
||||
if (contentType == null) contentType = "application/octet-stream";
|
||||
|
||||
// Upload zu S3
|
||||
String s3Key = "documents/" + UUID.randomUUID() + "_" + file.getName();
|
||||
try {
|
||||
s3Client.putObject(PutObjectRequest.builder()
|
||||
.bucket(bucketName)
|
||||
.key(s3Key)
|
||||
.contentType(contentType)
|
||||
.build(),
|
||||
RequestBody.fromFile(file));
|
||||
} catch (Exception e) {
|
||||
@@ -160,6 +170,7 @@ public class MassImportService {
|
||||
.build());
|
||||
|
||||
doc.setFilePath(s3Key);
|
||||
doc.setContentType(contentType);
|
||||
doc.setStatus(DocumentStatus.UPLOADED); // Jetzt ist es da!
|
||||
doc.setDocumentDate(date);
|
||||
doc.setLocation(location);
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE documents ADD COLUMN content_type character varying(255);
|
||||
Reference in New Issue
Block a user