Issue
I need to generate a bunch of xml files with data from my java based web system, that represent a whole export of another system based in XML. Such system will accept this import later.
My approach is to create all files in memory, then save each one as entries it to a zip also in memory, which later is served to the client.
The data flow is working perfectly, but somehow the output is a blank file. I think I got wrong the outputstream structure
This is the part that I might be getting wrong: ...
//ZIP creation in server memory
ByteArrayOutputStream datosEnMemoria = new ByteArrayOutputStream();
ZipOutputStream zipped_out = new ZipOutputStream(datosEnMemoria)
...
//close and zip entry
xmlData.append(Tangonet.terminarCargaRegistros());
byte[] xmlBinData = xmlData.toString().getBytes();
zipped_out.write(xmlBinData, 0, xmlBinData.length);
zipped_out.closeEntry();
}
byte[] zipped_out_size = zipped_out.toString().getBytes();
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename=cierresZ_a_tangonet" + java.time.LocalDate.now() + ".zip");
response.setHeader("Content-length", "" + zipped_out_size.length);
response.setHeader("Content-Type", "application/zip");
response.setHeader("Content-Type", "application/octet-stream");
response.setHeader("Content-Transfer-Encoding", " binary");
//closing zip and send it to client
zipped_out.flush();
zipped_out.close();
// out.flush();
// out.close();
This is the full code:
@RequestMapping(value = "/cierreZ/exportar", method = RequestMethod.GET)
public void cierreZExportar(@ModelAttribute InformesFinancierosForm informesFinancierosForm, HttpServletRequest request, HttpServletResponse response) throws IOException {
HttpSession session = request.getSession(true);
String fechaInicio = null;
String fechaFin = null;
if (session.getAttribute("mesActual") != null) {
informesFinancierosForm.setFechaInicio("01-" + informesFinancierosForm.getMes());
informesFinancierosForm.setFechaFin(new SimpleDateFormat("dd-MM-yyyy").format(DateUtil.getUltimoDiaDelMes(DateUtil.traduceDateDate((String) session.getAttribute("fechaIni")))));
fechaInicio = informesFinancierosForm.getFechaInicio();
fechaFin = informesFinancierosForm.getFechaFin();
} else {
fechaInicio = (String) session.getAttribute("fechaIni");
fechaFin = (String) session.getAttribute("fechaFin");
}
if (informeService.isRangoFechaValido(informesFinancierosForm.getSalasSeleccionadas(), fechaInicio)) {
if (!(fechaInicio.compareTo("") == 0) || (fechaFin.compareTo("") == 0)
|| informesFinancierosForm.getSalasSeleccionadas().length == 0) {
// ServletOutputStream out = response.getOutputStream();
List<InformeCierreZItemForm> listadoInfCierreZ = cierreZService.getCierres(informesFinancierosForm.getSalasSeleccionadas(), fechaInicio, fechaFin);
//ZIP creation in server memory
ByteArrayOutputStream datosEnMemoria = new ByteArrayOutputStream();
ZipOutputStream zipped_out = new ZipOutputStream(datosEnMemoria);
//filling zip with static xml files
for (int i = 0; i < Tangonet.documentos_estaticos_tangonet.length; i++) {
ZipEntry xmlFile = new ZipEntry(Tangonet.documentos_estaticos_tangonet[i][0] + ".xml");
zipped_out.putNextEntry(xmlFile);
StringBuilder xmlData = new StringBuilder();
xmlData.append(Tangonet.documentos_estaticos_tangonet[i][1]);
byte[] xmlBinData = xmlData.toString().getBytes();
zipped_out.write(xmlBinData, 0, xmlBinData.length);
zipped_out.closeEntry();
}
//filling zip with dynamic xml files
for (int i = 0; i < Tangonet.documentos_dinamicos_tangonet.length; i++) {
//dynamic xml creation
ZipEntry xmlFile = new ZipEntry(Tangonet.documentos_dinamicos_tangonet[i][0] + ".xml");
zipped_out.putNextEntry(xmlFile);
//xml schema
StringBuilder xmlData = new StringBuilder();
xmlData.append(Tangonet.documentos_dinamicos_tangonet[i][1]);
//xml data rows
for (InformeCierreZItemForm informeCierreZActual : listadoInfCierreZ) {
Sala salaActual = informeCierreZActual.getSala();
CierrezList CierresZ = cierreZService.getCierresZ(salaActual, fechaInicio, fechaFin);
//fiscal data in rows
Tangonet datosFiscalesCierrezActual = tangonetDatos.getDatosFiscales(salaActual);
for (Cierrez cierreActual : CierresZ) {
if (Tangonet.documentos_dinamicos_tangonet[i][0].equals("Comp_de_FacturaciĆ³n_para_Cobranza_Centralizada___GVA12")) {
xmlData.append(datosFiscalesCierrezActual.crearRegistroGVA12(cierreActual));
} else {
xmlData.append(datosFiscalesCierrezActual.crearRegistroGVA42(cierreActual));
}
}
}
//close and zip entry
xmlData.append(Tangonet.terminarCargaRegistros());
byte[] xmlBinData = xmlData.toString().getBytes();
zipped_out.write(xmlBinData, 0, xmlBinData.length);
zipped_out.closeEntry();
}
byte[] zipped_out_size = zipped_out.toString().getBytes();
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename=cierresZ_a_tangonet" + java.time.LocalDate.now() + ".zip");
response.setHeader("Content-length", "" + zipped_out_size.length);
response.setHeader("Content-Type", "application/zip");
response.setHeader("Content-Type", "application/octet-stream");
response.setHeader("Content-Transfer-Encoding", " binary");
//closing zip and send it to client
zipped_out.flush();
zipped_out.close();
// out.flush();
// out.close();
}
}
}
Solution
Zip file can be big, so don't generate it in memory. Write it straight to client.
Also:
Don't set
Content-Type
three times. It can only have one value.Don't specify
Content-Transfer-Encoding
. It's an email header, not an HTTP header.Since you'll be streaming, don't specify
Content-length
.
// headers must be set before streaming
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment;filename=cierresZ_a_tangonet" + java.time.LocalDate.now() + ".zip");
// stream straight to client
ZipOutputStream zipped_out = new ZipOutputStream(response.getOutputStream());
// Add zip entries and data here:
// Loop:
// zipped_out.putNextEntry(...)
// Generate XML, writing it straight to zipped_out
// Remember to flush any streams/writers wrapped around zipped_out
// Do not close zipped_out or wrappers of it
// If that cannot be prevented, use a CloseShieldOutputStream (from Commons IO)
// No need to call zipped_out.closeEntry()
// make sure to finish the zip stream
zipped_out.finish();
Answered By - Andreas
Answer Checked By - Mildred Charles (JavaFixing Admin)