【问题标题】:Download large file through spring mvc controller通过spring mvc控制器下载大文件
【发布时间】:2019-04-03 18:07:20
【问题描述】:

一旦用户单击“下载”按钮,我就有控制器方法开始下载文件。对象列表可以包含多达 400 000 个的大量对象。当我将少量对象放入 csv 文件时 - 它工作正常。

@RequestMapping(value = "/downloadCSV")
	public void downloadCSV(HttpServletResponse response) throws IOException 
	{
	
		response.setContentType("text/csv");
		String reportName = "metrics.csv";
		response.setHeader("Content-disposition", "attachment;filename="+reportName);
 
		ArrayList<String> rows = new ArrayList<String>();
		rows.add("A, B, C, D, E");
		rows.add("\n");
 
		for (int i = 0; i < someList.size(); i++) {
			String row = metricsDownloadModelList.get(i).getContentId() 
					+ someList.get(i).getA() + ", "
					+ someList.get(i).getB() + ", "
					+ someList.get(i).getC() + ", "
					+ someList.get(i).getD() + ", "
					+ someList.get(i).getE()
					+ "\n";
			rows.add(row);
		}
 
		Iterator<String> iter = rows.iterator();
		while (iter.hasNext()) {
			String outputString = (String) iter.next();
			response.getOutputStream().print(outputString);
		}
 
		response.getOutputStream().flush();

	}

但是当我将列表中的对象数量增加到 1000 或更多时,它 .给我一个错误:

执行控制器时出错 { org.apache.coyote.http11.HeadersTooLargeException: 尝试向响应头写入比缓冲区可用空间更多的数据。增加连接器上的 maxHttpHeaderSize 或将更少的数据写入响应标头。

我可以在不修改我的 servlet 配置文件的情况下解决我的问题吗?有没有其他方法可以解决这个问题?

【问题讨论】:

  • yuo 应该增加 servlet 容器中的标头大小。在 tomcat 中,这是在 server.xml 文件中完成的
  • @AngeloImmediate 它会影响我团队计划的其他部分吗?我害怕改变配置。我应该给 maxHttpHeaderSize 赋予什么价值
  • 它应该不会改变团队。该属性只是告诉 servlet 容器增加标头尺寸。关于他的价值,这取决于您的情况。我想 5MB 就足够了
  • @AngeloImmediate。我刚刚更改为 5MB 并重新加载我的服务器。但仍然得到同样的错误。有什么我应该检查或解决问题的吗?
  • 这也很奇怪,因为我可以在没有任何特殊配置的情况下下载一个巨大的文件。但是我看到的是您正在手动“构建” csv 文件。为什么?这很不常见

标签: java spring spring-mvc


【解决方案1】:

为了下载文件,我将执行以下操作:

  • 创建一个临时 CSV 文件
  • 下载文件

为了做到这一点,我会编写这种控制器:

@RequestMapping(method = { RequestMethod.GET }, value = { "/downloadCsv" })
public ResponseEntity<InputStreamResource>  downloadCSV()
{
    try
    {
            String fileName = "test.csv";
            //Create here your CSV file
            File theCsv = new File(fileName);
            HttpHeaders respHeaders = new HttpHeaders();
            MediaType mediaType = new MediaType("text","csv");
            respHeaders.setContentType(mediaType);
            respHeaders.setContentDispositionFormData("attachment", fileName);
            InputStreamResource isr = new InputStreamResource(new FileInputStream(theCsv));
            return new ResponseEntity<InputStreamResource>(isr, respHeaders, HttpStatus.OK);
    }
    catch (Exception e)
    {
        String messagge = "Error in CSV creation; "+e.getMessage();
        logger.error(messagge, e);
        return new ResponseEntity<InputStreamResource>(HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

通过使用这种控制器,我可以下载非常大的文件

安杰洛

【讨论】:

  • 由于catch子句上方的括号,此代码无法编译。
  • 同样会抛出异常,因为找不到文件路径。
  • 这取决于您自己的上下文;我无法解决。确保您必须使代码适应您的上下文
  • 它与上下文没有任何关系。如果文件不存在,那么你会吃掉 fileNot found 异常,因为输入流是从现有文件中读取的。请添加 if(!theCsv.exists()) { theCsv.createNewFile(); // 在文件系统上创建你的文件 }
  • 如果您觉得我的评论语气有点刺耳,我很抱歉 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-05-09
  • 1970-01-01
  • 1970-01-01
  • 2019-01-02
  • 2016-09-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多