ajax下載文件


 

 今天遇到這樣一個需求,將查查出來的數據導出來,不是將所有的數據導出來,而是要導出滿足條件的數據,也就是說下載的時候要將查詢的條件傳到后台。

例如: 先查詢課程性質是選修的課程然后導出來:

 

前台封裝條件的form:

        <form class="layui-form layui-col-md12 x-so" id="queryCourseForm">
            <%--隱藏兩個,一個當前頁,一個頁號--%>
                <%--當前頁--%>
                <input type="hidden" name="pageNum"/>
                <input type="hidden" name="pageSize"/>

           <div class="layui-input-inline">
                <input type="text" name="coursenamecn"  placeholder="請輸入課程中文名稱" autocomplete="off" class="layui-input">
            </div>
            <div class="layui-input-inline">
                <select name="courseplatform">
                    <option value="">請選擇課程平台</option>
                    <option value="通識教育">通識教育</option>
                    <option value="學科基礎課">學科基礎課</option>
                    <option value="專業課程">專業課程</option>
                    <option value="個性培養">個性培養</option>
                    <option value="教學環節">教學環節</option>
                </select>
            </div>

            <div class="layui-input-inline">
                <select name="coursenature">
                    <option value="">請選擇課程性質</option>
                    <option value="必修">必修</option>
                    <option value="選修">選修</option>
                </select>
            </div>
            <div class="layui-input-inline">
                <select name="credit">
                    <option value="">請選擇課程學分</option>
                    <option value="0-2">0-2</option>
                    <option value="2-4">2-4</option>
                    <option value="4-1000">4分以上</option>
                </select>
            </div>

            <button class="layui-btn" type="button" onclick="queryCourseFYBtn()"><i class="layui-icon">&#xe615;</i></button>
        </form>

 

后台springMCV接收查詢條件並且生成一個excel文件到本地並且提供下載:

package cn.xm.jwxt.controller.trainScheme;

import cn.xm.jwxt.service.trainScheme.CourseBaseInfoService;
import cn.xm.jwxt.utils.*;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @Author: qlq
 * @Description 導出課程信息到Excel中
 * @Date: 10:11 2018/4/29
 */
@Controller
public class ExtCourseExcel {

    @Autowired
    private CourseBaseInfoService courseBaseInfoService;
    private Logger logger = Logger.getLogger(ExtCourseExcel.class);
    //1.先從緩存中取數據,看能取到取不到

    //2.寫入excel到本地

    //3.打開流提供下載
    //1.查詢數據
    public List<Map<String, Object>> getCourseBaseInfosByCondition(@RequestParam Map<String, Object> condition) {
        List<Map<String, Object>> datas = null;
        try {
            datas =  courseBaseInfoService.getCourseBaseInfosByCondition(condition);
        } catch (SQLException e) {
            logger.error("導出課程信息的時候查詢數據庫出錯",e);
        }
        return datas;
    }


    //2.寫文件到excel中

    /**
     * 寫數據到本地磁盤
     * @param datas 課程數據
     * @param fileQualifyName   文件全路徑(比如C:/USER/XXX.excel)
     */
    public void writeCourse2LocalExcel(List<Map<String,Object>> datas,String fileQualifyName){
        String[] title = { "序號", "課程編號", "課程平台","課程性質","中文名稱","英文名稱","學分/學時", "周學時分配","計分方式" };
        //2.1寫入表頭信息
        // 創建一個工作簿
        HSSFWorkbook workbook = new HSSFWorkbook();
        // 創建一個工作表sheet
        HSSFSheet sheet = workbook.createSheet();
        // 設置列寬
        this.setColumnWidth(sheet, 9);
        // 創建第一行
        HSSFRow row = sheet.createRow(0);
        // 創建一個單元格
        HSSFCell cell = null;
        // 創建表頭
        for (int i = 0; i < title.length; i++) {
            cell = row.createCell(i);
            // 設置樣式
            HSSFCellStyle cellStyle = workbook.createCellStyle();
            cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 設置字體居中
            // 設置字體
            HSSFFont font = workbook.createFont();
            font.setFontName("宋體");
            font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);// 字體加粗
            // font.setFontHeight((short)12);
            font.setFontHeightInPoints((short) 13);
            cellStyle.setFont(font);
            cell.setCellStyle(cellStyle);
            cell.setCellValue(title[i]);
        }


        // 2.2寫入數據
        // 從第二行開始追加數據
        for (int i = 1, length_1 = (datas.size() + 1); i < length_1; i++) {
            // 創建第i行
            HSSFRow nextRow = sheet.createRow(i);
            // 設置樣式
            HSSFCellStyle cellStyle = workbook.createCellStyle();
            cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 設置字體居中
            // 獲取數據(一條數據)
            Map<String, Object> course = datas.get(i - 1);
            for (int j = 0; j < 9; j++) {
                HSSFCell cell2 = nextRow.createCell(j);
                cell2.setCellStyle(cellStyle);
                if (j == 0) {
                    cell2.setCellValue(i);//第一列是序號
                    continue;
                }
                if (j == 1) {
                    cell2.setCellValue(course.get("courseNum").toString());//課程編號
                    continue;
                }
                if (j == 2) {
                    cell2.setCellValue(course.get("coursePlatform").toString());//課程平台
                    continue;
                }
                if (j == 3) {
                    cell2.setCellValue(course.get("courseNature").toString());//課程性質
                    continue;
                }
                if (j == 4) {
                    cell2.setCellValue(course.get("courseNameCN").toString());//中文名稱
                    continue;
                }
                if (j == 5) {
                    cell2.setCellValue(course.get("courseNameEN").toString());//英文名稱
                    continue;
                }
                if (j == 6) {
                    cell2.setCellValue(course.get("credit").toString()+"/"+course.get("courseHour").toString());//學分/學時
                    continue;
                }
                if (j == 7) {
                    cell2.setCellValue(course.get("weeklyHour").toString());//周學時
                    continue;
                }
                if (j == 8) {
                    cell2.setCellValue(course.get("scoringWay").toString());//計分方式
                    continue;
                }
            }
        }


        // 創建一個文件
        File file = new File(fileQualifyName);
        // 獲取文件的父文件夾並刪除文件夾下面的文件
        File parentFile = file.getParentFile();
        // 獲取父文件夾下面的所有文件
        File[] listFiles = parentFile.listFiles();
        if (parentFile != null && parentFile.isDirectory()) {
            for (File fi : listFiles) {
                // 刪除文件
                fi.delete();
            }
        }
        // 如果存在就刪除
        if (file.exists()) {
            file.delete();
        }
        try {
            file.createNewFile();
            // 打開文件流並寫入文件
            FileOutputStream outputStream = org.apache.commons.io.FileUtils.openOutputStream(file);
            workbook.write(outputStream);
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 設置列寬的函數
     * @param sheet 對哪個sheet進行設置,
     * @param colNum
     */
    private  void setColumnWidth(HSSFSheet sheet, int colNum) {
        for (int i = 0; i < colNum; i++) {
            int v = 0;
            v = Math.round(Float.parseFloat("15.0") * 37F);
            v = Math.round(Float.parseFloat("20.0") * 267.5F);
            sheet.setColumnWidth(i, v);
        }
    }

    //3.打開流提供下載
    @RequestMapping("/downCourses")
    public void down(HttpServletRequest request, HttpServletResponse response,@RequestParam Map condition){
        //1.查詢數據
        List<Map<String, Object>> datas = this.getCourseBaseInfosByCondition(condition);
        //2.寫入excel
        String dir = ResourcesUtil.getValue("path","courseExcelFile");
        String fileName = DefaultValue.COURSE_DEFAULT_FILENAME;
        String fileQualifyName =  dir + fileName;//生成的excel名字
        this.writeCourse2LocalExcel(datas,fileQualifyName);//寫入數據(生成文件)
        //3.打開流提供下載
        //獲取輸入流
        try {
            InputStream bis = new BufferedInputStream(new FileInputStream(new File(fileQualifyName)));
            fileName = URLEncoder.encode(fileName,"UTF-8");
            //設置文件下載頭
            response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
            //1.設置文件ContentType類型,這樣設置,會自動判斷下載文件類型
            response.setContentType("multipart/form-data");
            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
            int len = 0;
            while((len = bis.read()) != -1){
                out.write(len);
                out.flush();
            }
            out.close();
        } catch (Exception e) {
            logger.error("下載課程信息出錯!",e);
        }
    }
}

 

接下來嘗試用ajax的post提交表單進行下載:

            $.ajax({
                url:contextPath+"/downCourses.do",
                type:'post',
                async:true,
                data:$("#queryCourseForm").serialize(),//攜帶查詢條件
                success:function () {
                   layer.close(index);
                }
            });

結果:響應頭正確,數據也正確的傳到后台,但是未下載文件:

 

 

 總結:

  即使ajax請求到一個controller在跳轉到下載的controller上也不能下載,百度了一下總結下原因:發現原來jQuery的ajax回調已經把response的數據傻瓜式的以字符串的方式解析.

 

 解決辦法:

  • 第一種:將傳條件的以表單提交的方式進行(推薦這種)-----這種方式也可以用來頁面跳轉
            $("#queryCourseForm").attr("action",contextPath+"/downCourses.do");//改變表單的提交地址為下載的地址
            $("#queryCourseForm").submit();//提交表單

 

  • 第二種:以window.location.href="xxx"的方式請求下載地址
            window.location.href=contextPath+"/downCourses.do"

  這種方法需要自己手動的拼接地址傳遞參數。get請求攜帶參數的方式:   xxxx.html?username=xxx&password=xxxx

 

  • 第三種:動態創建表單加到fbody中,最后刪除表單(推薦這種,可以將組合條件的值也動態的加入表單中)
    //動態創建表單加到fbody中,最后刪除表單
    var queryForm = $("#queryCourseForm");
    var exportForm = $("<form action='/downCourses.do' method='post'></form>")     
    exportForm.html(queryForm.html());
    $(document.body).append(exportForm);
    exportForm.submit();
    exportForm.remove();

注意:動態form必須加到DOM樹,否則會報異常:Form submission canceled because the form is not connected。而且提交完需要刪除元素。

 

進一步完善代碼:

    function download() {
        try {
            var queryForm = $("#queryCourseForm");
            var exportForm = $("<form action='/downCourses.do' method='post'></form>")
            exportForm.html(queryForm.html());
            $(document.body).append(exportForm);
            exportForm.submit();
        } catch (e) {
            console.log(e);
        } finally {
            exportForm.remove();
        }
    }

 

補充:    有時候上面查詢條件到不了第二個動態表單中,需要手動添加查詢條件到表單中,如下:

function extTaizhang(){
    //動態創建表單加到fbody中,最后刪除表單
    var queryForm = $("#queryTaizhangForm");
    var exportForm = $("<form action='"+baseurl+"/extSafeHatTaizhang.do' method='post'></form>")     
    
    exportForm.append("<input type='hidden' name='userName' value='"+$("[name='userName']").val()+"'/>")
    exportForm.append("<input type='hidden' name='idCard' value='"+$("[name='idCard']").val()+"'/>")
    exportForm.append("<input type='hidden' name='safeHatNum' value='"+$("[name='safeHatNum']").val()+"'/>")
    alert(exportForm.serialize());
    $(document.body).append(exportForm);
    exportForm.submit();
    exportForm.remove(); 
}

 

進一步封裝如下: (第一個參數是form元素的ID,也就是查詢條件所在的form,第二個參數是下載的URL,會自動遍歷條件並拼接查詢條件)

function exportExcel(formId, url) {
    try {
        var queryForm = $("#" + formId);
        var exportForm = $("<form action='" + url + "' method='post'></form>")
        
        queryForm.find("input").each(function() {
            var name = $(this).attr("name");
            var value = $(this).val();
            exportForm.append("<input type='hidden' name='" + name + "' value='" + value + "'/>")
        });
        
        queryForm.find("select").each(function() {
            var name = $(this).attr("name");
            var value = $(this).val();
            exportForm.append("<input type='hidden' name='" + name + "' value='" + value + "'/>")
        });
        
        $(document.body).append(exportForm);
        exportForm.submit();
    } catch (e) {
        console.log(e);
    } finally {
        exportForm.remove();
    }
}

調用代碼:

exportExcel('listPageForm', 'extOperationCharge.do')

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM