java - 提供服务器中生成并存储在内存中的 zip 文件

标签 java spring servlets server zip

我需要使用来 self 的基于 java 的 Web 系统的数据生成一堆 xml 文件,这些文件代表另一个基于 XML 的系统的完整导出。此类系统稍后将接受此导入。

我的方法是在内存中创建所有文件,然后将每个文件作为条目保存到内存中的 zip 中,稍后将其提供给客户端。

数据流工作正常,但不知何故输出是一个空白文件。我想我弄错了输出流结构

这是我可能会出错的部分: ...

 //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();

这是完整的代码:

@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();
            }
        }
    }

最佳答案

Zip 文件可能很大,因此不要在内存中生成它。直接写给客户。

另外:

  • 不要设置 Content-Type 三次。它只能有一个值。

  • 不要指定Content-Transfer-Encoding。这是电子邮件 header ,而不是 HTTP header 。

  • 由于您要进行流式传输,因此请勿指定 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();

关于java - 提供服务器中生成并存储在内存中的 zip 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58597942/

相关文章:

java - PHP 使用 cUrl 将数组发送到 java servlet

java - Android/Java 库

java - 在 Spring security 3.0 中使用基于组的访问控制

java - 错误: Parameter out was not defined for stored procedure

java - 如何创建将添加新属性源的自定义注释

java - 如何避免复制粘贴 hasRole 或 hasPermission 注释?

java - Spring/在一个bean的工厂方法中访问当前的applicationContext

java - 使用 Spring 4 @Transactional + Hibernate 4 + EHCache 忽略缓存

java - JPA 无交易 Activity

servlets - 为什么带有空格的 cookie 值会带引号到达客户端?