Springboot+vue+poi查询mysql下载excel(GET、POST爬坑)

本文要解决的问题

  • 利用Spring 下载excel的参数传递问题
  • POST请求无法直接下载文档,报错excel打不开
  • 下载接口response返回乱码问题

背景

最近项目用到了excel导出功能,在实际的运用中,场景覆盖了GET和POST请求。接入的过程中,遇到了不少坑:

坑1,乱码问题(GET和POST中均遇到了该问题)。

Response截图
返回头

坑2,post请求无法直接发送请求下载excel文档

原因:我们在后台改变了响应头的内容:
Content-Type: application/vnd.ms-excel
导致post请求无法识别这种消息头,导致无法直接下载。
解决方法:
改成使用form表单提交方式即可

具体实现

GET

js文件(重点:设置responseType)

// 全部下载
export const download_all = async sendData => {
    return await request({
        url: '/api/downloadAll',
        method: 'get',
        params: sendData,
        responseType: 'blob'    //这个很重要!!!
    });
};

vue文件

allDownload() {
  this.$confirm('此操作会将符合检索条件的全部结果下载, 是否继续?', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(() => {
    let startTime = null;
    let endTime = null;
    if (this.timeValue !== null && this.timeValue.length === 2) {
      startTime = this.timeValue[0];
      endTime = this.timeValue[1];
    }
    api.download_all({
      taskName: this.taskName,
      startTime: startTime,
      endTime: endTime
    }).then(res => {
      let fileName = res.headers['content-disposition'].split('=')[1];
      // 获取文件名
      let objectUrl = URL.createObjectURL(new Blob([res.data]));
      // 文件地址
      const link = document.createElement('a');
      link.download = fileName;
      link.href = objectUrl;
      link.click();
    });
  }).catch(() => {
    this.$message({
      type: 'info',
      message: '已取消下载'
    });
  });
}

POST

js文件

// 多选下载
export const download_multi = async sendData => {
    return await request({
        url: '/api/downloadMulti',
        method: 'post',
        data: sendData
    });
};

vue文件(采用form表单提交来完成)

multiDownload() {
  this.$confirm('此操作会将所勾选的全部结果下载, 是否继续?', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(() => {
    var form = document.createElement("form");
    form.style.display = 'none';
    form.action = '/api/downloadMulti';
    form.method = "post";
    document.body.appendChild(form);
    let params = {list: this.getIdList()};  //参数
    for(var key in params){
      var input = document.createElement("input");
      input.type = "hidden";
      input.name = key;
      input.value = params[key];
      form.appendChild(input);
    }
    form.submit();
    form.remove();
  }).catch((e) => {
    this.$message({
      type: 'info',
      message: '已取消下载'
    });
    console.log(e);
  });
}

Controller

@RequestMapping(value = "api/downloadMulti", method = {RequestMethod.POST})
public void downloadMulti(HttpServletRequest request, HttpServletResponse response) throws IOException {
    String list = request.getParameter("list");
    String[] split = list.split(",");
    List<Long> idList = new ArrayList<>();
    for (String id: split) {
        idList.add(Long.valueOf(id));
    }
    List<Result> resultList = service.getResult(idList);    //具体的service不展示,查数据库
    service.getExcel(resultList, response);
}

@RequestMapping(value = "api/downloadAll", method = {RequestMethod.GET})
public void downloadAll(@RequestParam(value = "taskName", required = false) String taskName,
                        @RequestParam(value = "startTime", required = false) String startTime,
                        @RequestParam(value = "endTime", required = false) String endTime,
                        HttpServletResponse response
) throws IOException {
    List<Result> resultList = service.getAllResult(taskName, startTime, endTime);  //具体的service不展示,查数据库
    service.getExcel(resultList, response);
}

Service

public void getExcel(List<Result> resultList, HttpServletResponse response) throws IOException {
    //表头数据
    String[] header = {"任务名称", "产生时间", "备注"};
    //声明一个工作簿
    HSSFWorkbook workbook = new HSSFWorkbook();
    //生成一个表格,设置表格名称为"结果表"
    HSSFSheet sheet = workbook.createSheet("结果");
    //设置表格列宽度为10个字节
    sheet.setDefaultColumnWidth(10);
    //创建第一行表头
    HSSFRow headrow = sheet.createRow(0);
    //遍历添加表头
    for (int i = 0; i < header.length; i++) {
        //创建一个单元格
        HSSFCell cell = headrow.createCell(i);
        //创建一个内容对象
        HSSFRichTextString text = new HSSFRichTextString(header[i]);
        //将内容对象的文字内容写入到单元格中
        cell.setCellValue(text);
    }
    int count = 1;
    //模拟遍历结果集,把内容加入表格
    for (Result result: resultList) {
        List<String> rowList = new ArrayList<>(13);
        rowList.add(result.getTaskName());
        rowList.add(result.getCreateTime());
        rowList.add(result.getComment());
        int subCount = 0;
        HSSFRow row = sheet.createRow(count);
        for (String str: rowList) {
            HSSFCell cell = row.createCell(subCount);
            HSSFRichTextString text = new HSSFRichTextString(str);
            cell.setCellValue(text);
            subCount ++;
        }
        count ++;
    }
    response.setCharacterEncoding("utf-8");
    //准备将Excel的输出流通过response输出到页面下载
    response.setContentType("application/vnd.ms-excel");
    //这后面可以设置导出Excel的名称,此例中名为result.xls
    response.setHeader("Content-disposition", "attachment;filename=result.xls");
    //刷新缓冲
    response.flushBuffer();
    //workbook将Excel写入到response的输出流中,供页面下载
    workbook.write(response.getOutputStream());
}

另外一种POST方式

export const download_sensitive_result = async sendData => {
    return await request({
        url: '/api/v3/dbscan/downloadSensitiveResult',
        method: 'post',
        data: sendData,
        responseType: 'blob'
    });
};
api.download_sensitive_result({
    aList: aList,
    appkey: this.value_appkey,
    dataStatus: this.dataStatus
}).then(res => {
    console.log(res.status);
    if (res.status === 200) {
        this.$message({
                message: '成功获取下载数据',
                type: 'success'
                            });
        let fileName = res.headers['content-disposition'].split('=')[1];
        // 获取文件名
        let objectUrl = URL.createObjectURL(new Blob([res.data]));
        // 文件地址
                            const link = document.createElement('a');
        link.download = fileName;
        link.href = objectUrl;
        link.click();
    } else if (res.status === 202) {
        this.$message({
                message: '没找到相关数据',
                type: 'info'
                            });
    } else {
        this.$message({
          message: '获取数据报错',
          type: 'error'
        });
    }
});
@RequestMapping(value = "downloadSensitiveResult", method = {RequestMethod.POST})
    public Result downloadSensitiveResult(@RequestBody String resultStr, HttpServletResponse response) {
        Map<String, Object> resultMap = JsonUtil.toMap(resultStr, String.class, Object.class);
        String aStr = JsonUtil.fromObject(resultMap.get("aList"));
        List<String> aList = JsonUtil.toList(aStr, String.class);
        String appkey = (String) resultMap.get("appkey");
        Boolean dataStatus = (Boolean) resultMap.get("dataStatus");
        Map<String, Object> result;
        result = aService.getSensitiveResultExcel(aList, appkey, dataStatus, response);
        if ((Integer) result.get("code") == 200) {
            return Result.success(result.get("msg"));
        } else if ((Integer) result.get("code") == 200){
            return Result.fail(202, result.get("msg").toString());
        } else {
            return Result.fail(500, result.get("msg").toString());
        }
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351