Je veux créer un fichier .zip contenant les fichiers compressés que je reçois du backend, puis envoyer ce fichier à l'utilisateur. Cela fait 2 jours que je cherche la réponse et que je ne trouve pas la solution appropriée, peut-être que tu peux m'aider :)
Pour l'instant, le code est comme ceci: (Je sais que je ne devrais pas tout faire dans le contrôleur de ressort, mais ne vous inquiétez pas, c'est juste pour des tests, pour trouver le moyen de le faire fonctionner)
@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();
}
Mais le problème est que, en utilisant le code, lorsque je saisis l'URL: localhost: 8080/Zip, je reçois le fichier: test.Zip.html au lieu du fichier .Zip.
Je n'ai aucune idée de ce que je peux faire d'autre. J'essayais également de remplacer ByteArrayOuputStream par quelque chose comme:
OutputStream outputStream = response.getOutputStream();
et définissez la méthode sur void donc il ne retourne rien, mais il a créé un fichier .Zip qui a été endommagé.
Sur mon macbook après avoir décompressé le fichier test.Zip je recevais test.Zip.cpgz qui me donnait à nouveau le fichier test.Zip et ainsi de suite.
Sous Windows, le fichier .Zip était endommagé, comme je l’ai dit, et ne pouvait même pas l’ouvrir.
Je suppose aussi que la suppression de l'extension .html sera automatiquement la meilleure option, mais comment? J'espère que ce n'est pas aussi difficile que cela semble être :) merci
semble être résolu. J'ai remplacé:
response.setContentType("application/Zip");
avec:
@RequestMapping(value = "/Zip", produces="application/Zip")
Et maintenant, je suis clair, beau fichier .Zip :)
Si certains d'entre vous ont une proposition meilleure ou plus rapide, ou veulent juste donner un conseil, alors allez-y, je suis curieux.
@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();
}
J'utilise REST Web Service
de Spring Boot
et j'ai conçu les systèmes d'extrémité pour toujours renvoyer ResponseEntity
qu'il s'agisse de JSON
ou PDF
ou Zip
et j'ai proposé la solution suivante partiellement inspirée de denov's answer
dans cette question ainsi que d'une autre question où j'ai appris à convertir ZipOutputStream
en byte[]
afin de le transmettre à ResponseEntity
en tant que sortie du noeud final.
Quoi qu’il en soit, j’ai créé une classe d’utilitaire simple avec deux méthodes de téléchargement de fichier pdf
et Zip
@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);
}
}
Et maintenant, le noeud final peut facilement renvoyer ResponseEntity<?>
, comme indiqué ci-dessous, à l'aide des données byte[]
et des en-têtes personnalisés spécifiquement adaptés à pdf
ou Zip
.
@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);
}
La BinaryOutputWrapper
est une simple classe POJO
immuable que j'ai créée avec private byte[] data;
et org.springframework.http.HttpHeaders headers;
comme champs afin de renvoyer à la fois data
et headers
à partir de la méthode d'utilitaire.