UploadController.java
package de.aikiit.bilanzanalyser.upload;
import de.aikiit.bilanzanalyser.reader.BilanzRowParserResult;
import de.aikiit.bilanzanalyser.reader.BilanzRowParserStatistic;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.util.HtmlUtils;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@Log4j2
@RestController
public final class UploadController {
private static final String UPLOAD_DIR = "uploads-bilanz-analyser";
private final UploadAnalysisService uploadAnalysisService;
private final SourceService sourceService;
@Value("${java.io.tmpdir}")
private String tempDir;
public UploadController(UploadAnalysisService uploadAnalysisService, SourceService sourceService) {
this.uploadAnalysisService = uploadAnalysisService;
this.sourceService = sourceService;
}
@GetMapping("/upload")
public ModelAndView upload() {
ModelAndView mav = new ModelAndView("upload");
mav.addObject("worksheets", sourceService.getSources());
mav.addObject("selectedWorksheet", "Ausgaben");
return mav;
}
@PostMapping("/upload")
public ModelAndView handleFileUpload(@RequestParam("file") MultipartFile file, @RequestParam("selectedWorksheet") String selectedWorksheet) {
// Create ModelAndView for the "upload" view
ModelAndView mav = new ModelAndView("upload");
mav.addObject("worksheets", sourceService.getSources());
// prevent mingling with selected worksheet and properly escape user-provided value
if (!sourceService.getSources().contains(selectedWorksheet)) {
mav.addObject("message", "Invalid worksheet selected");
return mav;
}
String escapedSelectedWorksheet = HtmlUtils.htmlEscape(selectedWorksheet);
mav.addObject("selectedWorksheet", escapedSelectedWorksheet);
if (file.isEmpty()) {
mav.addObject("message", "Please select a file to upload");
return mav;
}
if (!"application/vnd.oasis.opendocument.spreadsheet".equals(file.getContentType())) {
mav.addObject("message", "Only ODS spreadsheet files allowed");
return mav;
}
try {
// Create directory if not exists under current temp base dir
Path uploadDir = Paths.get(tempDir + File.separatorChar + UPLOAD_DIR);
Files.createDirectories(uploadDir);
// Save file
Path destination = Paths.get(uploadDir.toString(), System.currentTimeMillis() + ".ods");
file.transferTo(destination);
// Process rows and cleanup afterwards
BilanzRowParserResult result = uploadAnalysisService.processFile(selectedWorksheet, destination);
Files.delete(destination);
// flush to DB asynchronously
uploadAnalysisService.flushDataIntoDatabase(result);
mav.addObject("sucmessage", "File uploaded successfully. Processed " + result.rowCount() + " rows in table " + escapedSelectedWorksheet);
mav.addObject("statistic", BilanzRowParserStatistic.from(result));
} catch (IOException e) {
log.error(e.getMessage());
mav.addObject("message", "Upload failed: " + e.getMessage());
}
return mav;
}
}