From 1791fd909d6cc3493207f4bb582792c6e877e878 Mon Sep 17 00:00:00 2001 From: Dmitry Isaenko Date: Wed, 10 Jan 2024 21:59:11 +0300 Subject: [PATCH] Add Download ability --- .../ru/redrise/marinesco/BookController.java | 3 - .../redrise/marinesco/DownloadController.java | 89 +++++++++++++++++++ .../marinesco/library/InpxScanner.java | 20 ++--- .../settings/ApplicationSettings.java | 13 +++ src/main/resources/templates/book.html | 2 +- 5 files changed, 110 insertions(+), 17 deletions(-) create mode 100644 src/main/java/ru/redrise/marinesco/DownloadController.java diff --git a/src/main/java/ru/redrise/marinesco/BookController.java b/src/main/java/ru/redrise/marinesco/BookController.java index 63d46aa..0cca2eb 100644 --- a/src/main/java/ru/redrise/marinesco/BookController.java +++ b/src/main/java/ru/redrise/marinesco/BookController.java @@ -6,12 +6,9 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; -import lombok.extern.slf4j.Slf4j; import ru.redrise.marinesco.data.InpEntryRepository; -import ru.redrise.marinesco.library.Author; import ru.redrise.marinesco.library.InpEntry; -@Slf4j @Controller @RequestMapping("/book") public class BookController { diff --git a/src/main/java/ru/redrise/marinesco/DownloadController.java b/src/main/java/ru/redrise/marinesco/DownloadController.java new file mode 100644 index 0000000..70be12d --- /dev/null +++ b/src/main/java/ru/redrise/marinesco/DownloadController.java @@ -0,0 +1,89 @@ +package ru.redrise.marinesco; + +import java.io.File; +import java.io.FileOutputStream; +import java.nio.charset.StandardCharsets; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import org.springframework.core.io.FileSystemResource; +import org.springframework.http.ContentDisposition; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import ru.redrise.marinesco.settings.ApplicationSettings; + +@Slf4j +@Controller +@RequestMapping("/download") +public class DownloadController { + + private String filesLocation; + + public DownloadController(ApplicationSettings applicationSettings) { + this.filesLocation = applicationSettings.getFilesLocation(); + } + + @GetMapping(value = "/") + public void getMethodName(@RequestParam String container, + @RequestParam String file, + HttpServletResponse response) throws Exception { + + final FileSystemResource libraryLocation = new FileSystemResource(filesLocation + File.separator + container); + try (ZipInputStream zipInputStream = new ZipInputStream(libraryLocation.getInputStream())) { + ZipEntry zipEntry = zipInputStream.getNextEntry(); + + while (zipEntry != null) { + if (zipEntry.getName().contains(file)) { + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); + response.setHeader(HttpHeaders.CONTENT_DISPOSITION, ContentDisposition.attachment() + .filename(file+".fb2", StandardCharsets.UTF_8) //TODO: fix + .build() + .toString()); + ServletOutputStream outStream = response.getOutputStream(); + sendFile(zipEntry.getSize(), zipInputStream, outStream); + outStream.flush(); + outStream.close(); + return; + } + + zipEntry = zipInputStream.getNextEntry(); + } + } + throw new Exception("file not found " + + filesLocation + File.separator + container + " → " + file); + } + + private void sendFile(long fileSize, + ZipInputStream zipInputStream, + ServletOutputStream outStream) throws Exception { + + int blockSize = 0x200; + + if (fileSize < 0x200) + blockSize = (int) fileSize; + + byte[] block = new byte[blockSize]; + long i = 0; + + while (true) { + int actuallyRead = zipInputStream.read(block); + outStream.write(block, 0, actuallyRead); + i += actuallyRead; + if ((i + blockSize) > fileSize) { + blockSize = (int) (fileSize - i); + if (blockSize == 0) + break; + block = new byte[blockSize]; + } + } + } + +} diff --git a/src/main/java/ru/redrise/marinesco/library/InpxScanner.java b/src/main/java/ru/redrise/marinesco/library/InpxScanner.java index 4b715e6..f58a577 100644 --- a/src/main/java/ru/redrise/marinesco/library/InpxScanner.java +++ b/src/main/java/ru/redrise/marinesco/library/InpxScanner.java @@ -17,27 +17,29 @@ import ru.redrise.marinesco.data.AuthorRepository; import ru.redrise.marinesco.data.GenreRepository; import ru.redrise.marinesco.data.InpEntryRepository; import ru.redrise.marinesco.data.LibraryMetadataRepository; +import ru.redrise.marinesco.settings.ApplicationSettings; @Slf4j @Component -@ConfigurationProperties(prefix = "marinesco.library") public class InpxScanner implements Runnable { private static volatile Thread parser; private static volatile String lastRunErrors; - private String filesLocation = ""; - private LibraryMetadata libraryMetadata; private LibraryMetadataRepository libraryMetadataRepository; private AuthorRepository authorRepository; private GenreRepository genreRepository; private InpEntryRepository inpEntryRepository; - public InpxScanner(AuthorRepository authorRepository, + private String filesLocation; + + public InpxScanner(ApplicationSettings applicationSettings, + AuthorRepository authorRepository, GenreRepository genreRepository, InpEntryRepository inpEntryRepository, LibraryMetadataRepository libraryMetadataRepository) { + this.filesLocation = applicationSettings.getFilesLocation(); this.authorRepository = authorRepository; this.genreRepository = genreRepository; this.inpEntryRepository = inpEntryRepository; @@ -47,7 +49,7 @@ public class InpxScanner implements Runnable { /* * @return true if executed, false if already running */ - public boolean reScan(){ + public boolean reScan() { if (parser == null || !parser.isAlive()) { parser = new Thread(this); parser.start(); @@ -190,14 +192,6 @@ public class InpxScanner implements Runnable { return i + 1 < content.length && (content[i + 1] == '\r'); } - public String getFilesLocation() { - return filesLocation; - } - - public void setFilesLocation(String location) { - filesLocation = location; - } - public static String getLastRunErrors() { return lastRunErrors; } diff --git a/src/main/java/ru/redrise/marinesco/settings/ApplicationSettings.java b/src/main/java/ru/redrise/marinesco/settings/ApplicationSettings.java index b59f35c..0f3471c 100644 --- a/src/main/java/ru/redrise/marinesco/settings/ApplicationSettings.java +++ b/src/main/java/ru/redrise/marinesco/settings/ApplicationSettings.java @@ -1,10 +1,14 @@ package ru.redrise.marinesco.settings; +import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; @Component +@ConfigurationProperties(prefix = "marinesco.library") public class ApplicationSettings { private static final String ALLOW_REGISTRATION = "allow_registration"; + + private String filesLocation = ""; private KeyValueRepository keyValueRepository; @@ -34,4 +38,13 @@ public class ApplicationSettings { public synchronized boolean isRegistrationAllowed() { return registrationAllowed; } + + public String getFilesLocation() { + return filesLocation; + } + + public void setFilesLocation(String location) { + filesLocation = location; + } + } diff --git a/src/main/resources/templates/book.html b/src/main/resources/templates/book.html index ed58289..54ec738 100644 --- a/src/main/resources/templates/book.html +++ b/src/main/resources/templates/book.html @@ -29,7 +29,7 @@

- +