バックエンドから受信した圧縮ファイルを含む.Zipファイルを作成し、このファイルをユーザーに送信します。 2日間、私は答えを探していて、適切な解決策を見つけることができませんでした、多分あなたは私を助けることができます:)
今のところ、コードは次のようになっています:(私はそれをスプリングコントローラーですべて行うべきではないことを知っていますが、それを気にしないでください、それはテスト目的で、それを動作させる方法を見つけるためです)
@RequestMapping(value = "/Zip")
public byte[] zipFiles(HttpServletResponse response) throws IOException{
//setting headers
response.setContentType("application/Zip");
response.setStatus(HttpServletResponse.SC_OK);
response.addHeader("Content-Disposition", "attachment; filename=\"test.Zip\"");
//creating byteArray stream, make it bufforable and passing this buffor to ZipOutputStream
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(byteArrayOutputStream);
ZipOutputStream zipOutputStream = new ZipOutputStream(bufferedOutputStream);
//simple file list, just for tests
ArrayList<File> files = new ArrayList<>(2);
files.add(new File("README.md"));
//packing files
for (File file : files) {
//new Zip entry and copying inputstream with file to zipOutputStream, after all closing streams
zipOutputStream.putNextEntry(new ZipEntry(file.getName()));
FileInputStream fileInputStream = new FileInputStream(file);
IOUtils.copy(fileInputStream, zipOutputStream);
fileInputStream.close();
zipOutputStream.closeEntry();
}
if (zipOutputStream != null) {
zipOutputStream.finish();
zipOutputStream.flush();
IOUtils.closeQuietly(zipOutputStream);
}
IOUtils.closeQuietly(bufferedOutputStream);
IOUtils.closeQuietly(byteArrayOutputStream);
return byteArrayOutputStream.toByteArray();
}
しかし、問題は、コードを使用して、URL:localhost:8080/Zipを入力すると、.Zipファイルではなくtest.Zip.htmlが取得されることです。
他に何ができるかわかりません。また、ByteArrayOuputStreamを次のようなものに置き換えようとしました。
OutputStream outputStream = response.getOutputStream();
そして、メソッドをvoidに設定して、何も返さないが、破損した.Zipファイルを作成しましたか?
test.Zipを解凍した後、私のMacbookでtest.Zip.cpgzを取得していましたが、これは再びtest.Zipファイルなどを提供してくれました。
私が言ったように、Windowsでは.Zipファイルが破損しており、開くことさえできませんでした。
また、.html拡張子を自動的に削除するのが最善の選択肢になると思いますが、どうすればいいですか?それがそうであるように難しいことではないことを願っています:)ありがとう
解決されたようです。私は置き換えました:
response.setContentType("application/Zip");
で:
@RequestMapping(value = "/Zip", produces="application/Zip")
そして今、私は明確な、美しい.Zipファイルを取得します:)
あなたのいずれかがより良いまたはより速い提案を持っているか、単にアドバイスをしたい場合は、先に進みます、私は興味があります。
@RequestMapping(value="/Zip", produces="application/Zip")
public void zipFiles(HttpServletResponse response) throws IOException {
//setting headers
response.setStatus(HttpServletResponse.SC_OK);
response.addHeader("Content-Disposition", "attachment; filename=\"test.Zip\"");
ZipOutputStream zipOutputStream = new ZipOutputStream(response.getOutputStream());
// create a list to add files to be zipped
ArrayList<File> files = new ArrayList<>(2);
files.add(new File("README.md"));
// package files
for (File file : files) {
//new Zip entry and copying inputstream with file to zipOutputStream, after all closing streams
zipOutputStream.putNextEntry(new ZipEntry(file.getName()));
FileInputStream fileInputStream = new FileInputStream(file);
IOUtils.copy(fileInputStream, zipOutputStream);
fileInputStream.close();
zipOutputStream.closeEntry();
}
zipOutputStream.close();
}
REST Web Service
のSpring Boot
を使用しており、ResponseEntity
またはJSON
またはPDF
であるかどうかにかかわらず、常にZip
を返すようにエンドポイントを設計しました。この質問のdenov's answer
と別の 質問 に触発された次の解決策を思い付きました。ここでは、ZipOutputStream
をbyte[]
に順番に変換する方法を学びました。エンドポイントの出力としてResponseEntity
にフィードします。
とにかく、pdf
およびZip
ファイルのダウンロード用の2つのメソッドを持つ単純なユーティリティクラスを作成しました
@Component
public class FileUtil {
public BinaryOutputWrapper prepDownloadAsPDF(String filename) throws IOException {
Path fileLocation = Paths.get(filename);
byte[] data = Files.readAllBytes(fileLocation);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType("application/pdf"));
String outputFilename = "output.pdf";
headers.setContentDispositionFormData(outputFilename, outputFilename);
headers.setCacheControl("must-revalidate, post-check=0, pre-check=0");
return new BinaryOutputWrapper(data, headers);
}
public BinaryOutputWrapper prepDownloadAsZIP(List<String> filenames) throws IOException {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType("application/Zip"));
String outputFilename = "output.Zip";
headers.setContentDispositionFormData(outputFilename, outputFilename);
headers.setCacheControl("must-revalidate, post-check=0, pre-check=0");
ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
ZipOutputStream zipOutputStream = new ZipOutputStream(byteOutputStream);
for(String filename: filenames) {
File file = new File(filename);
zipOutputStream.putNextEntry(new ZipEntry(filename));
FileInputStream fileInputStream = new FileInputStream(file);
IOUtils.copy(fileInputStream, zipOutputStream);
fileInputStream.close();
zipOutputStream.closeEntry();
}
zipOutputStream.close();
return new BinaryOutputWrapper(byteOutputStream.toByteArray(), headers);
}
}
そして今、エンドポイントはResponseEntity<?>
データとpdf
またはZip
用に特別に調整されたカスタムヘッダーを使用して、以下に示すようにbyte[]
を簡単に返すことができます。
@GetMapping("/somepath/pdf")
public ResponseEntity<?> generatePDF() {
BinaryOutputWrapper output = new BinaryOutputWrapper();
try {
String inputFile = "sample.pdf";
output = fileUtil.prepDownloadAsPDF(inputFile);
//or invoke prepDownloadAsZIP(...) with a list of filenames
} catch (IOException e) {
e.printStackTrace();
//Do something when exception is thrown
}
return new ResponseEntity<>(output.getData(), output.getHeaders(), HttpStatus.OK);
}
BinaryOutputWrapper
は、ユーティリティからPOJO
とdata
の両方を返すためにprivate byte[] data;
とorg.springframework.http.HttpHeaders headers;
をフィールドとして作成した単純な不変headers
クラスです。方法。