【问题标题】:How to download a file from AJAX request in Liferay serveResource(-, -) method如何在 Liferay serveResource(-, -) 方法中从 AJAX 请求下载文件
【发布时间】:2015-05-22 06:41:38
【问题描述】:

我有这样的要求:我正在发出 AJAX 请求以将一些数据传递给服务器。在我的服务器中,我正在使用该数据创建一个文件。

“现在的问题是文件没有下载到客户端”。

(我正在使用 Apache POI API 从给定数据创建 excel 文件)。 谁能帮我做这件事?

这是我的代码:

(发出 AJAX 请求的代码)

<script>
    function downloadUploadedBacklogs () {

        try {
            var table_data = [];

            var count = jQuery("#backlogTable tr:first td" ).length;
            jQuery("#<portlet:namespace/>noOfColumns").val(count);
            var index = 0;
            jQuery('tr').each(function(){

                var row_data = '';
                jQuery('td', this).each(function(){
                    row_data += jQuery(this).text() + '=';   
                });   
                table_data.push(row_data+";");

            });
            jQuery("#<portlet:namespace/>backlogDataForDownload").val(table_data);
            jQuery("#<portlet:namespace/>cmd").val("downloadUploadedBacklogs");
            alert('cmd: ' + jQuery("#<portlet:namespace/>cmd").val());  
            var formData = jQuery('#<portlet:namespace/>backlogImportForm').serialize();

            jQuery.ajax({
                url:'<%=resourceURL%>',
                data:formData,
                type: "post",
                success: function(data) {

                }
            });
            alert('form submitted');

        } catch(e) {
            alert('eroor: ' + e);
        }
    };
</script>

Java 代码 serveResource(-,-) 方法

/*
*   serveResource(-, -) method to process the client request
*/
public void serveResource(ResourceRequest resourceRequest,
            ResourceResponse resourceResponse) throws IOException,
            PortletException {


        String cmd = ParamUtil.getString(resourceRequest,"cmd");
        System.out.println("**********************cmd*************"+cmd);

        if(cmd!="") {
            if("downloadUploadedBacklogs".equalsIgnoreCase(cmd)){

                String backlogData = ParamUtil.getString(resourceRequest, "backlogDataForDownload");
                ImportBulkDataUtil.downloadUploaded("Backlogs", resourceRequest,resourceResponse);
            } 
        }
}

/ * ImportBulkDataUtil.downloadUploaded(-, -, -) 方法创建excel文件 /

public static void downloadUploaded(String schema, ResourceRequest resourceRequest,ResourceResponse resourceResponse) {

        String excelSheetName = ParamUtil.getString(resourceRequest,"excelSheetName");

        try {
            resourceResponse.setContentType("application/vnd.ms-excel");
            resourceResponse.addProperty(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename="+excelSheetName+"_Template.xls");

            OutputStream outputStream=resourceResponse.getPortletOutputStream();
            //converting the POI object as excel readble object
            HSSFWorkbook objHSSFWorkbook=new HSSFWorkbook();
            HSSFSheet objHSSFSheet=objHSSFWorkbook.createSheet(excelSheetName+"_Template");

            //set the name of the workbook 
            Name name=objHSSFWorkbook.createName();
            name.setNameName(excelSheetName+"_Template");

            objHSSFSheet.autoSizeColumn((short)2);

            // create freeze pane (locking) top row
            objHSSFSheet.createFreezePane(0, 1);

            // Setting column width
            String excelData = StringPool.BLANK;
            if((schema.equalsIgnoreCase("Backlogs"))){
                System.out.println("Inside BacklogsCreation..........");
                objHSSFSheet.setColumnWidth(0, 10000);
                objHSSFSheet.setColumnWidth(1, 7000);
                objHSSFSheet.setColumnWidth(2, 7000);
                objHSSFSheet.setColumnWidth(3, 7000);
                objHSSFSheet.setColumnWidth(4, 7000);
                objHSSFSheet.setColumnWidth(5, 5000);
                objHSSFSheet.setColumnWidth(6, 5000);
                objHSSFSheet.setColumnWidth(7, 7000);
                objHSSFSheet.setColumnWidth(8, 7000);
                excelData = ParamUtil.getString(resourceRequest,"backlogDataForDownload");
            }
            System.out.println("downloadUploaded excelTableData: " + excelData);

             // Header creation logic

            HSSFRow objHSSFRowHeader = objHSSFSheet.createRow(0);
            objHSSFRowHeader.setHeightInPoints((2*objHSSFSheet.getDefaultRowHeightInPoints()));
            CellStyle objHssfCellStyleHeader = objHSSFWorkbook.createCellStyle();
            objHssfCellStyleHeader.setFillBackgroundColor((short)135);
            objHssfCellStyleHeader.setAlignment(objHssfCellStyleHeader.ALIGN_CENTER);
            objHssfCellStyleHeader.setWrapText(true);

            // Apply font styles to cell styles
            HSSFFont objHssfFontHeader = objHSSFWorkbook.createFont();
            objHssfFontHeader.setFontName("Arial");
            objHssfFontHeader.setColor(HSSFColor.WHITE.index);

            HSSFColor lightGrayHeader =  setColor(objHSSFWorkbook,(byte) 0x00, (byte)0x20,(byte) 0x60);
            objHssfCellStyleHeader.setFillForegroundColor(lightGrayHeader.getIndex());
            objHssfCellStyleHeader.setFillPattern(CellStyle.SOLID_FOREGROUND);

            objHssfFontHeader.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
            objHssfFontHeader.setFontHeightInPoints((short)12);
            objHssfCellStyleHeader.setFont(objHssfFontHeader);
            objHssfCellStyleHeader.setWrapText(true);

            // first column about Backlog title
            HSSFCell objBacklogTitleCell = objHSSFRowHeader.createCell(0);
            objBacklogTitleCell.setCellValue("Backlog");
            objBacklogTitleCell.setCellStyle(objHssfCellStyleHeader);   

            // second column about Description
            HSSFCell objBacklogDescCell = objHSSFRowHeader.createCell(1);
            objBacklogDescCell.setCellValue("Description");
            objBacklogDescCell.setCellStyle(objHssfCellStyleHeader);

            // third column about Project
            HSSFCell objProjectNameCell = objHSSFRowHeader.createCell(2);
            objProjectNameCell.setCellValue("Project");
            objProjectNameCell.setCellStyle(objHssfCellStyleHeader);
            setComment("Project which the backlog belongs to", objProjectNameCell);

            // fourth column about Category
            HSSFCell objCategoryNameCell = objHSSFRowHeader.createCell(3);
            objCategoryNameCell.setCellValue("Category");
            objCategoryNameCell.setCellStyle(objHssfCellStyleHeader);
            setComment("Category which the backlog belongs to (i.e. Bug, New Requirement, Enhancement)", objCategoryNameCell);

            // fifth column about Group
            HSSFCell objGroupNameCell = objHSSFRowHeader.createCell(4);
            objGroupNameCell.setCellValue("Group");
            objGroupNameCell.setCellStyle(objHssfCellStyleHeader);
            setComment("Group which the backlog belongs to", objGroupNameCell);

            // sixth column about Est. Start Date
            HSSFCell objEstStartDtCell = objHSSFRowHeader.createCell(5);
            objEstStartDtCell.setCellValue("Est. Start Date");
            objEstStartDtCell.setCellStyle(objHssfCellStyleHeader);
            setComment("Date Format: dd/mm/yyyy", objEstStartDtCell);

            // seventh column about Est. End Date
            HSSFCell objEstEndDtCell = objHSSFRowHeader.createCell(6);
            objEstEndDtCell.setCellValue("Est. End Date");
            objEstEndDtCell.setCellStyle(objHssfCellStyleHeader);
            setComment("Date Format: dd/mm/yyyy", objEstEndDtCell);

            // fifth column about Group
            HSSFCell objStatusCell = objHSSFRowHeader.createCell(7);
            objStatusCell.setCellValue("Status");
            objStatusCell.setCellStyle(objHssfCellStyleHeader);

            String excelTableDataRecords[] = excelData.split(";");
            for(int i=1; i<excelTableDataRecords.length; i++) {

                HSSFRow objHSSFRow = objHSSFSheet.createRow(i);
                objHSSFRow.setHeightInPoints((2*objHSSFSheet.getDefaultRowHeightInPoints()));

                excelTableDataRecords[i] = excelTableDataRecords[i].substring(0, (excelTableDataRecords[i].length()-2));
                if(excelTableDataRecords[i].charAt(0) == ',') {
                    excelTableDataRecords[i] = excelTableDataRecords[i].substring(1, (excelTableDataRecords[i].length()));
                }
                String excelTableColumns[] = excelTableDataRecords[i].split("::");

                for(int j=0; j<excelTableColumns.length; j++) {

                        // Apply font styles to cell styles
                        HSSFFont objHssfFont = objHSSFWorkbook.createFont();
                        objHssfFont.setFontName("Arial");
                        CellStyle objHssfCellStyle = objHSSFWorkbook.createCellStyle();
                        objHssfFont.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);
                        objHssfFont.setColor(HSSFColor.BLACK.index);
                        objHssfFont.setFontHeightInPoints((short)10);

                        objHssfCellStyle.setWrapText(true);
                        objHssfCellStyle.setFont(objHssfFont);
                        // other column about Backlog title
                        HSSFCell objNewHSSFCellFirstNameAdd = objHSSFRow.createCell(j);
                        objNewHSSFCellFirstNameAdd.setCellValue(excelTableColumns[j]);
                        objNewHSSFCellFirstNameAdd.setCellStyle(objHssfCellStyle);
                }
            }

            objHSSFWorkbook.write(outputStream);
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("Exception raised in downloadUploaded() method to download uploaded excel data");
        }
    }

谁能帮助我?

【问题讨论】:

  • 我也对resourceURL进行了同样的尝试。但是由于我的数据是动态变化的,所以我需要更新 resourceURL 参数值。但是当我更新它时,只有部分数据会进入我的 serveResource(-,-) 方法
  • 我用resourceURL 发现的另一个问题是URL 有一些长度限制。所以当数据很大时会出问题..
  • 你能看到服务器发送的一些数据吗?是根本不发送数据还是只是不在客户端下载文件?
  • 我可以在客户端的控制台看到响应数据

标签: java javascript jquery ajax liferay


【解决方案1】:

只需将请求作为 GET,返回文件的字节流作为响应并相应地设置标题(取决于文件 excel/pdf 的格式),然后在客户端只需在新选项卡中打开响应,浏览器就会启动文件下载。

【讨论】:

  • 我试过没有办法,你能提供它的示例参考
【解决方案2】:

可能有 2 个问题。要么你根本不发送文件,要么 ajax 没有下载它。

从您的代码中,我可以看到您在响应的输出流中写入文件,因此我怀疑该部分正在工作。如果它包含response body 中的数据,也许您可​​以打开浏览器开发工具查看来自服务器的响应。

第二部分很复杂,因为从 JS 的性质(安全原因)你不能直接在 JS 本身中下载(下载不会自己开始)。

您需要使用 iframe 并将文件 url 附加到并提交表单以开始下载

$("body").append("<iframe src='" + data.message + "' style='display: none;' ></iframe>");

或

您可以使用新的 HTML5 FileAPI 在一个请求中为您执行此操作。只需为响应指定blob (responseType: 'blob') 类型,从响应正文转换URL,将其附加到新创建的锚&lt;a&gt; 元素的href 属性并单击它。

更多详情请参阅this 帖子。

希望对您有所帮助。

【讨论】:

  • 感谢您的建议,我会尽力让您知道
  • 我们正在使用 FileAPI,因此您可以在单个请求中下载文件,而第一种方法是您需要将文件保存在某个地方并发送它的 url 并发出另一个请求以下载它。
【解决方案3】:

只需使用参数调用以下函数:

url - 您要请求文件的位置
数据 - 以防万一 发送一些数据
pageIndex - div id 你想在其中附加 iframe 并且如果没有 # ,它将被删除。

this.ajaxDownload = function(url, data,pageId) {
                pageId = '#' + pageId;
                 if ($(pageId + ' #download_iframe').length == 0) {
                     $("<iframe id='download_iframe' style='display: none' src='about:blank'></iframe>").appendTo(pageId);
                 }

                 var input = "<input type='hidden' name='requestJson' value='" + JSON.stringify(data) + "'>";

                 var iframe_html = "<html>"+
                     "<head>"+
                     "</head>"+
                     "<body>"+
                     "<form id='downloadForm' method='POST' action='" + url +"'>" +input+ "</form>" +
                     "</body>"+
                     "</html>";

                 var ifrm = $(pageId + ' #download_iframe')[0].contentWindow.document;
                 ifrm.open();
                 ifrm.write(iframe_html);
                 ifrm.close();

                 $(pageId + ' #download_iframe').contents().find("#downloadForm").submit();
 }

【讨论】:

  • 我收到异常,例如:contentWindow undefined, ifrm.open(); // 无法打开
  • @ChandanPrakashSharma 您没有正确发送 pageId 尝试将 div id 发送给它。您可以通过在我们检查长度相等的条件下调试代码来确保您的页面 id 运行良好归零
【解决方案4】:

我认为这只是您的 ajax 命令不符合要求。 请参阅 jquery ajax 文档。

似乎 ajax jquery 抱怨 xml 数据下载,但它与 excel 数据格式不对应。

在 ajax 中将 dataType 设置为“text”,并在将生成的文件发送到客户端之前进行良好的 MIME 类型。它使下载的 excel 文件被浏览器解释为真正的 excel 文件。

【讨论】:

    【解决方案5】:

    您可以将 POI HSSFWorkbook 的内容写入 ByteArrayOutputStream,然后在 Liferay 的 PortletResponseUtil sendFile() 方法中使用流的 toByteArray() 方法,如下所示:

    PortletResponseUtil.sendFile(resourceRequest, resourceResponse, "FILENAME", byteStream.toByteArray(), "CONTENT_TYPE");
    

    而不是直接写入资源响应。

    但是,可能出于安全原因,(Javascript 不能直接将文件写入客户端)您不能通过 Ajax 执行此操作。

    您也可以将您在 JS 代码中计算的原始数据保存到隐藏输入中,然后通过常规表单提交将其传递给服务器。

    【讨论】:

    • 嗨 Tryfon,谢谢您的回复。我会尝试并让您知道状态
    • 我在下面尝试过(但它没有解决我的问题): ByteArrayOutputStream byteArrOStream= new ByteArrayOutputStream(); objHSSFWorkbook.write(byteArrOStream); PortletResponseUtil.sendFile(resourceRequest, resourceResponse, excelSheetName+"_Template.xls", byteArrOStream.toByteArray(), "application/vnd.ms-excel");你能把我接下来需要做的事情放在更多的地方吗?
    猜你喜欢
    • 2017-12-01
    • 1970-01-01
    • 2014-01-16
    相关资源
    最近更新 更多