java通过poi生成excel并下载出现文件打不开、文件格式和文件扩展名无效问题的分析与解决

需求描述:
需要完成这样一个功能:后台通过poi生成excle,前台点击按钮可直接下载。
代码逻辑(核心部分):

第一种:

 public String generatePlanExcel(@RequestParam(value = "planId") int planId, HttpServletRequest request, HttpServletResponse response) throws Exception{
        // 1.创建新的Excel工作簿(workbook)
        // 1.1 07版本的Excel需要XSSFWorkbook对象
        Workbook workbook = new XSSFWorkbook();
        // 2.使用workbook创建sheet
        // 2.1在Excel工作簿中建一工作表(sheet),其名为缺省值 Sheet0
        //Sheet sheet = workbook.createSheet();

        // 2.2如要新建一名为"预案详细信息"的工作表,其语句为:
        Sheet sheet = workbook.createSheet("预案详细信息");
		...
		String fileName = planRecordAndResources.getName() + ".xlsx";
		ByteArrayOutputStream os = new ByteArrayOutputStream();
		workbook.write(os);
		byte[] content = os.toByteArray();
		InputStream is = new ByteArrayInputStream(content);
		
		// 设置response参数,可以打开下载页面
		response.reset();
		response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
		response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName,"utf-8"));
		response.setHeader("Content-Length", String.valueOf(is.available()));
		response.setCharacterEncoding("UTF-8");
		ServletOutputStream sout = response.getOutputStream();
		BufferedInputStream bis = null;
		BufferedOutputStream bos = null;
		
		try {
		   bis = new BufferedInputStream(is);
		   bos = new BufferedOutputStream(sout);
		   byte[] buff = new byte[2048];
		   int bytesRead;
		   // Simple read/write loop.
		   while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
		       bos.write(buff, 0, bytesRead);
		   }
		} catch (Exception e) {
		   logger.error("导出excel出现异常:", e);
		} finally {
		   if (bis != null){
		       bis.close();
		   }
		   if (bos != null){
		       bos.close();
		   }
		}
		...
	}

第二种:

 public String generatePlanExcel(@RequestParam(value = "planId") int planId, HttpServletRequest request, HttpServletResponse response) throws Exception{
        // 1.创建新的Excel工作簿(workbook)
        // 1.1 07版本的Excel需要XSSFWorkbook对象
        Workbook workbook = new XSSFWorkbook();
        // 2.使用workbook创建sheet
        // 2.1在Excel工作簿中建一工作表(sheet),其名为缺省值 Sheet0
        //Sheet sheet = workbook.createSheet();

        // 2.2如要新建一名为"预案详细信息"的工作表,其语句为:
        Sheet sheet = workbook.createSheet("预案详细信息");
        //临时文件
        File tempFile = null;
        try {

            //要保存的文件名
            String filename = planRecordAndResources.getName() + ".xlsx";
            //要保存的根目录
            String rootDir = request.getSession().getServletContext().getRealPath("/");
            //要保存的目录路径
            String path = rootDir + File.separator + "tempfile";
            File saveDir = new File(path);
            if (!saveDir.exists()) {
                saveDir.mkdirs();// 如果文件不存在则创建文件夹
            }
            //文件路径
            path = path + File.separator + filename;
            //初始化临时文件
            tempFile = new File(path);
            //输出流
            OutputStream out = new FileOutputStream(tempFile);
            try {
                //保存文件
                workbook.write(out);
            } catch (IOException e) {
                e.printStackTrace();
            }
            out.close();


            // 以流的形式下载文件。
            BufferedInputStream fis = new BufferedInputStream(new FileInputStream(path));

            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            fis.close();
            // 清空response
            response.reset();
            // 设置response的Header
            response.setCharacterEncoding("UTF-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName,"utf-8"));
            response.setHeader("Content-Length", "" + tempFile.length());
            response.setHeader("Pragma", "no-cache");
            response.setHeader("Cache-Control", "no-cache");
            response.setContentType("application/vnd.ms-excel;charset=UTF-8");
            OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
            toClient.write(buffer);
            toClient.flush();
            toClient.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (tempFile != null && tempFile.exists()) {
                tempFile.delete();// 删除临时文件
            }
        }

问题描述:
接口写完之后,通过swaggerpostman进行测试发现文件无法正常打开。

下载的文件是这样的:
在这里插入图片描述
用WPS打开该文件是这样的:
在这里插入图片描述
用office Excel打开该文件是这样的:
在这里插入图片描述
在这里插入图片描述
刚开始感觉是自身代码出现了问题,但是通过第二种先生成临时文件的方式实现excel下载,我在本地打开临时生成的excel文件是没有问题的,通过流的方式转换和下载之后就仍然出现上面的问题。于是乎感觉可能是response设置的问题,便开始了长达2小时的百度求知。
查到的解决方式很多都是重复的,大致上可以分为:
1.说response中必须有这行设置

response.setHeader("Content-Length", fis.available()+"")

2.说创建xls与xlsx工作薄的不同

导出xlsx格式,创建工作薄的时候用:

Workbook workbook = new XSSFWorkbook();

导出xls格式,创建工作薄的时候用:

Workbook workbook = new HSSFWorkbook();

3.说response.setContentType设置的不同

导出xlsx格式设置ContentType需要:

response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");

导出xls格式设置ContentType需要:

response.setContentType("application/vnd.ms-excel");

在网上找到的所有的解决方法都尝试仍然无效之后,找到了这篇博客
使用httpServletResponse和POI写入excle时标题和内容乱码的问题解决
发现,如果单纯没有和前台对接的前提下,使用swagger或者postman进行接口测试,无论怎么修改response的header都没有办法下载出正常的excel文件,但是通过在浏览器中直接输入url的方式,就得到了正常的可打开且格式正确的excel。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
至于为何通过swagger和postman无法下载处正常的可打开的excel文件望知情大佬指证。

  • 17
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值