利用swagger组件测试excel下载,打开文件乱码。

最近项目遇到个问题,就是利用swagger下载excel时,得到的文件打开总是乱码,首先怀疑是response的content-type有问题,将application试遍了,“x-msdownload”,“vnd.ms-excel”,“vnd.openxmlformats-officedocument.spreadsheetml.sheet”,“octet-stream”这些试了都不行,具体的类型对应文件参考一下链接:https://blog.csdn.net/xiaojia_boke/article/details/81140647

利用swagger组件测试excel下载,打开文件乱码。_第1张图片

然后怀疑是不是写入文件后再回填response这种方式导致文件流操作有问题,因为写入本地和服务器的文件都是可以正常打开的,但是将文件写入response后就乱码了。于是将业务数据解析后的workbook直接写入response测试,结果还是乱码,排除这种猜测。

然后在网上查阅资料,发现下载excel方式都大同小异,都是解析出workbook然后写入response,差异无非就是是否通过写临时文件来缓存写入下。后来想到是不是自己代码的问题,然后从网上现扒个代码,然后在另外一个工程里直接测试,因为那个工程没有集成swagger,所以直接写了个get请求,然后通过浏览器访问,结果下载的excel可以正常打开,对比代码,实现方式没啥差异,于是把工程的下载excel功能也通过浏览器直接访问来测试,结果果然是好使的,于是果断怀疑到swagger身上。。

中间还用postman测试了下,之前没用postman测过这种下载文件的功能,这次新get到postman的2个使用技巧:

1、下载文件就在send旁边这个下拉框里,选择“send and download”,不过这里下载的文件名称都是默认的response,不是我后台代码定义的那个文件名。

利用swagger组件测试excel下载,打开文件乱码。_第2张图片

利用swagger组件测试excel下载,打开文件乱码。_第3张图片

2、后台下载的接口入参是@RequestBody对象的,postman在测试时在body-》raw-》选中json来填写入参,见上面的截图。

 

最后来说说swagger的配置修改,在注解swagger配置时,给Docket加上配置new Docket(DocumentationType.SWAGGER_2)
                .produces(Sets.newHashSet("application/octet-stream")),说明返回的是文件流即可成功下载excel。

利用swagger组件测试excel下载,打开文件乱码。_第4张图片

中间也给这个Docket改过 new Docket(DocumentationType.SWAGGER_2)
                .consumes(Sets.newHashSet("application/octet-stream")),也给controller接口的@ApiOperation加过produces="application/octet-stream",后经测试发现是Docket.produces()起作用的。至于Docket的这些配置具体啥含义,需要接下来进一步研究。

 

最后附上后台下载的大概逻辑代码,欢迎各位提出修改意见。

1、controller的代码:

    @ApiOperation(value = "下载excel接口", notes = "前端页面点击下载操作时调用接口")
    @PostMapping("/downLoadRules")
    public void downLoadRules(
            @RequestBody @ApiParam(name = "rulesToDownLoad", value = "下载excel列表", required = true) List rulesToDownLoad,
            HttpServletResponse response) {

        if (CollectionUtils.isEmpty(rulesToDownLoad)) {
            logger.error("待下载请求为空");
        }
        // 当前日期,用于导出文件名称
        String fileName ="Download_Rule_" + DateUtil.getDate("yyyyMMddHHmmss") + ".xlsx";
        boolean result = downLoadService.exportExcel(rulesToDownLoad, response, fileName);
    }

2、解析后的workbook写入response:

public boolean exportExcel(List ruleModelList, HttpServletResponse response, String fileName){
        boolean downloadResult = false;
        response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        XSSFWorkbook workbook = getWorkBook(ruleModelList);
        if(workbook!=null){
            try{
                //遗留问题:文件过大,可能写入效率过低,待优化
                workbook.write(response.getOutputStream());
            }
            catch(Exception e){
                logger.error("导出excel,写入workbook异常:{}", e.getLocalizedMessage());
            }finally {
                try{
                    workbook.close();
                    downloadResult = true;
                }
                catch(IOException e){
                    logger.error("导出excel,关闭workbook异常:{}", e.getLocalizedMessage());
                }
            }
        }
        return downloadResult;
    }

3、根据业务解析出workbook:

private XSSFWorkbook getWorkBook(List ruleModelList) {
            //根据入参ruleModelList和模板templatePath解析出来的workbook对象
            FileInputStream excelFileInputStream = new FileInputStream(templatePath.getPath());
             XSSFWorkbook workbook = new XSSFWorkbook(excelFileInputStream);
            excelFileInputStream.close();

            。

            。

            。


        return workbook;
    }

 

后续:

前两天直接改的swagger的整体配置:

new Docket(DocumentationType.SWAGGER_2).produces(Sets.newHashSet("application/octet-stream"))

最近同事联调代码发现所有的rest请求从swagger测试请求都是流的形式,这显然是不行的,影响了别的接口功能。

后来从swagger测试,发现这里的Request Headers中Accept为“*/*”时下载的excel就不行,我在swagger配置为流"application/octet-stream"时,这里的Accept就是流的形式,然后下载的excel就是OK的。

利用swagger组件测试excel下载,打开文件乱码。_第5张图片

此处怀疑swagger默认是用json还是文本或者xml给解析了,考虑是不是我能在接口层面把这个请求的Accept绑定成流的形式,然后在接口定义的@PostMapping进入源码查看有好几个属性:

利用swagger组件测试excel下载,打开文件乱码。_第6张图片

感觉这个headers比较靠谱,直接给@PostMapping赋值如下:@PostMapping(value="/downLoadExcel", headers="application/octet-stream"),用swagger测试直接报错一堆js错误,还是配置不对,swagger不识别,然后在网上查阅资料,得给headers配置headers="Accept=application/octet-stream",再调试一切OK,说明这里的@PostMapping配置和swagger的配置有个对应关系,具体怎么映射,待后续研究明白了再补上~

 

 

 

你可能感兴趣的:(java代码)