You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Liferay Portlet下载Excel时获取PortletOutputStream抛出异常求助

Liferay Portlet Excel下载:解决getPortletOutputStream()抛出的IllegalStateException

在Liferay Portlet中实现Excel下载时,调用resourceResponse.getPortletOutputStream()抛出异常:

java.lang.IllegalStateException: Unable to obtain OutputStream because Writer is already in use

原因分析

  • 错误使用字符流处理二进制文件:Excel属于二进制格式,代码中用InputStreamReader、OutputStreamWriter这类字符流读写,会破坏文件结构,同时可能触发Portlet容器提前初始化Writer,导致后续无法获取OutputStream。
  • 响应头拼写错误:Content-disposition属性中的atachment是拼写错误,正确应为attachment,错误的响应头可能引发容器异常处理逻辑,间接导致Writer被占用。

解决方案

  • 改用字节流直接复制文件内容到输出流,避免字符转换操作。
  • 修正Content-disposition的拼写错误。
  • 确保代码中没有其他地方提前获取ResourceResponse的Writer(比如调用getWriter()方法)。

修正后的代码

public static void descargaFichero(ResourceRequest resourceRequest, ResourceResponse resourceResponse) throws Exception {
    HttpServletRequest request = PortalUtil.getOriginalServletRequest(PortalUtil.getHttpServletRequest(resourceRequest));
    OutputStream outputStream = null;
    InputStream is = null;
    File tempFile = null;
    
    try {
        String idDescarga = request.getParameter("id-descarga");
        String rutaFicheroDescarga = Encriptador.decrypt(ConstantesFlujos.CLAVE_ENCRIPTADO_JSON, idDescarga);
        
        String extension = FileUtil.getExtension(rutaFicheroDescarga);
        String nombreArchivo = String.format("%s%s.%s", 
                ConstantesFlujos.PREFIJO_NOMBRE_FICHERO_RENOVACION,
                fechaDesglosada(),
                extension);
        
        if(GestorLog.isInfoEnabled(clase)){
            GestorLog.info(clase, String.format("Descargando fichero temporal: '%s' a '%s'", rutaFicheroDescarga, nombreArchivo));
        }
        
        if (extension.equalsIgnoreCase("xls")) {
            resourceResponse.setContentType("application/vnd.ms-excel");
        } else {
            resourceResponse.setContentType("application/octet-stream");
        }
        
        // 修正拼写错误:atachment -> attachment
        ((PortletResponse) resourceResponse).addProperty("Content-disposition", String.format("attachment; filename=%s", nombreArchivo));
        
        tempFile = new File(rutaFicheroDescarga);
        
        outputStream = resourceResponse.getPortletOutputStream();
        is = new FileInputStream(tempFile);
        
        // 用字节流直接复制,避免字符转换
        byte[] buf = new byte[8192];
        int c = 0;
        while ((c = is.read(buf, 0, buf.length)) > 0) {
            outputStream.write(buf, 0, c);
            outputStream.flush();
        }
        
    } catch(Exception e){
        GestorLog.error(clase, "Error en el metodo descargaFichero: " + e.getMessage());
        throw e;
    } finally {
        // 按顺序关闭资源:先关闭输入流,再关闭输出流
        if (is != null) {
            is.close();
        }
        if (outputStream != null) {
            outputStream.close();
        }
        if (tempFile != null) {
            tempFile.delete();
        }
    }
}

内容的提问来源于stack exchange,提问作者Daniel Rodríguez Bravo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 14:01:42