1. 程式人生 > >JQuery 中 AJAX 如何實現 Excel 檔案 下載

JQuery 中 AJAX 如何實現 Excel 檔案 下載

我們知道,JQuery的ajax函式的返回型別只有xml、text、json、html等型別,沒有“流”型別,所以我們要實現ajax下載,不能夠使用相應的ajax函式進行檔案下載。但在js中 生成一個form,用這個form提交引數,並返回“流”型別的資料。在實現過程中,頁面也沒有進行重新整理。

注意,如果伺服器端是Spring MVC,則該server端必須支援 post方法且 content type 是 "application/x-www-form-urlencoded"

下面的例子均已除錯通過。

前端JS頁面例子:

mp.jsp

 manipulationHistory.downloadData = function() {
    	//定義一個form表單
    	var myform = $("<form></form>");
    	myform.attr('method','post')
    	myform.attr('action',"/manipulationHistory/exportManipulationInfo");
    	
    	var myProductId = $("<input type='hidden' name='productId' />")
    	myProductId.attr('value',$("#query-param-product-id").val());
    	
    	var myPurchaseOrderId = $("<input type='hidden' name='purchaseOrderId' />") 
    	myPurchaseOrderId.attr('value',$("#query-param-dispatched-po").val());
    	
    	var myWarehouseId = $("<input type='hidden' name='warehouseId' />") 
    	myWarehouseId.attr('value', $("#query-param-warehouse-id").val());
    	
    	var myRelatedOrderId = $("<input type='hidden' name='relatedOrderId' />") 
    	myRelatedOrderId.attr('value', $("#query-param-order-id").val());
    	
    	var myUpdateReason = $("<input type='hidden' name='updateReason' />") 
    	myUpdateReason.attr('value', $("#query-param-update-reason").val());
    	
    	var myStartTime = $("<input type='hidden' name='startTime' />") 
    	myStartTime.attr('value', $("#operate-time-start-value").val());
    	
    	var myEndTime = $("<input type='hidden' name='endTime' />") 
    	myEndTime.attr('value', $("#operate-time-end-value").val());
    	
    	myform.append(myProductId);
    	myform.append(myPurchaseOrderId); 
    	myform.append(myWarehouseId); 
    	myform.append(myRelatedOrderId); 
    	myform.append(myUpdateReason); 
    	myform.append(myStartTime); 
    	myform.append(myEndTime);
    	myform.appendTo('body').submit(); //must add this line for higher html spec  	
    };

後臺server端的java程式碼如下(用SPring MVC來支援)
/*
     * Ajax not support stream response message, so front page need to use form
     * to submit request with APPLICATION_FORM_URLENCODED
     */
    @Consumes({ MediaType.APPLICATION_FORM_URLENCODED })
    @RequestMapping(value = "/exportManipulationInfo", method = RequestMethod.POST)
    @ResponseBody
    public boolean exportManipulationInfo(HttpServletRequest request, HttpServletResponse response) {
        ManipulationInfoQuery manipulationInfoQuery = generateMHQuery(request);
        LOG.info("[IMS_INFO][exportManipulationInfo] received request: " + JsonHelper.toJson(manipulationInfoQuery));
        List<ManipulationInfo> resultList = manipulationHistoryPageService.getManipulationInfoListWithoutPage(manipulationInfoQuery);
        if (null == resultList || resultList.isEmpty()) {
            LOG.info(" no data retrieved for query: " + JsonHelper.toJson(manipulationInfoQuery));
        }
        return downLoadsExcel(resultList, response);
    }

    private ManipulationInfoQuery generateMHQuery(HttpServletRequest request) {
        ManipulationInfoQuery resultQuery = new ManipulationInfoQuery();
        resultQuery.setProductId(request.getParameter("productId"));
        resultQuery.setPurchaseOrderId(request.getParameter("purchaseOrderId"));
        String warehouseID = request.getParameter("warehouseId");
        if (StringUtils.isNotBlank(warehouseID)) {
            resultQuery.setWarehouseId(Integer.parseInt(warehouseID));
        } else {
            resultQuery.setWarehouseId(null);
        }
        resultQuery.setRelatedOrderId(request.getParameter("relatedOrderId"));
        resultQuery.setUpdateReason(request.getParameter("updateReason"));
        resultQuery.setStartTime(request.getParameter("startTime"));
        resultQuery.setEndTime(request.getParameter("endTime"));
        resultQuery.setPageInd(null);
        resultQuery.setPageSize(null);
        return resultQuery;
    }

    private boolean downLoadsExcel(List<ManipulationInfo> dataList, HttpServletResponse response) {
        FileOutputStream fos = null;
        try {
            HSSFWorkbook wb = new HSSFWorkbook();
            HSSFSheet sheet = wb.createSheet("ManipulationInfo_details");
            sheet.setDefaultColumnWidth(40);

            HSSFCellStyle style = wb.createCellStyle();
            style.setAlignment(HSSFCellStyle.ALIGN_LEFT);

            String fileName = "ManipulationInfoData-" + String.valueOf(System.currentTimeMillis()).substring(4, 13) + ".xls";
            fos = new FileOutputStream(fileName);

            // column name
            String[] label = { "index", "productId", "productName", "warehouseId", "warehouseName", "dispatchedPo", "relatedOrderId", "updateField", "action",
                    "result", "updateReason", "operator", "operateTime" };

            int columnNum = label.length;
            // set title column at line 0
            HSSFRow titleRow = sheet.createRow((int) 0);
            // the most left column is index of column
            HSSFCell titleCell = null;
            for (int n = 0; n < columnNum; n++) {
                titleCell = titleRow.createCell(n);
                titleCell.setCellType(HSSFCell.CELL_TYPE_STRING);
                titleCell.setCellValue(label[n]);
                titleCell.setCellStyle(style);
            }

            if (null != dataList && !dataList.isEmpty()) {
                for (int rowIndex = 0; rowIndex < dataList.size(); rowIndex++) {
                    ManipulationInfo item = dataList.get(rowIndex);
                    /*
                     * the line 0 is title line,so actual data line begins from
                     * the next one line.
                     */
                    HSSFRow row = sheet.createRow(rowIndex + 1);
                    String rowData[] = { item.getProductId(), item.getProductName(), item.getWarehouseId().toString(), item.getWarehouseName(),
                            item.getDispatchedPo(), item.getRelatedOrderId(), item.getUpdateField(), item.getAction(), item.getResult().toString(),
                            item.getUpdateReason(), item.getOperator(), item.getOperateTime() };

                    // create the most left column as index column
                    HSSFCell cell = row.createCell(0, HSSFCell.CELL_TYPE_NUMERIC);
                    cell.setCellValue(rowIndex + 1);
                    cell.setCellStyle(style);

                    // create the remaining cells at the same line
                    for (int columnIndex = 1; columnIndex < columnNum; columnIndex++) {
                        cell = row.createCell(columnIndex, HSSFCell.CELL_TYPE_STRING);
                        cell.setCellValue(rowData[columnIndex - 1]);
                        cell.setCellStyle(style);
                    }
                }
            } else {
                LOG.info(" no data retrieved");
            }

            // set all columns to automatically adjust column width
            for (int i = 0; i < columnNum; i++) {
                sheet.autoSizeColumn(i);
            }

            wb.write(fos); // write workbook into file .xls
            fos.flush(); // flush buffer to file
            fos.close(); // remember to close it
            if (wb != null) {
                response.reset();
                response.setContentType("application/vnd.ms-excel");
                response.setHeader("Content-Disposition", "filename=" + new String(fileName.getBytes(), "iso-8859-1"));
                OutputStream out = response.getOutputStream();
                wb.write(out);
                out.flush();
                out.close();
            }
        } catch (Exception e) {
            LOG.error( downLoadsExcel exception:" + e);
            return false;
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    LOG.error(" close FileOutputStream error:" + e);
                    return false;
                }
            }
        }

        return true;
    }

在上面的JAVA後端程式碼中,注意沒有@RequestBody來修飾傳入引數,這是因為如下說明:

關於@ResponseBody,@RequestBody,@PathVariable比較通俗的解釋就是: @PathVariable主要是用來處理URl路徑的問題,利用@PathVariable可以是實現在URL路徑中實現引數的隱藏效果。
@RequestBody主要是用來處理請求型別轉換問題,例如可以把json字串通過配置自動轉換為物件之類的。
@ResponseBody主要是用來處理返回型別轉換問題,例如可以把json字串通過配置自動轉換為物件之類的。
一般@ResponseBody,@RequestBody都是用來處理json和xml資料型別,不能用於傳統的html解析,因為@ResponseBody,@RequestBody都只是獲取內容而已,並不是整個html,所以在有用到json或者xml資料型別傳輸的時候才可以考慮使用@ResponseBody,@RequestBody這兩個註解,否則不要使用。

一個不錯的連線是:

http://blog.csdn.net/linzhiqiang0316/article/details/52328153