Grails动态创建可下载文件

4
简单来说:我可以创建一个文件,将其保存在文件系统中,然后创建一个包含指向该文件链接的页面,但是如果我想要一个包含许多文件链接的页面,这些文件可能不需要全部生成怎么办?
因此,我的用户在列表页面上点击一个链接,比如:
<g:link action="gimmeAFile" id="${myThingieInstance.id}">${fieldValue(bean: myThingieInstance, field: "id")}</g:link>

现在我有一个控制器,看起来像这样:

def gimmeAFile = {
  def lotsaLines = []
  //Do a ton of stuff that has lotsaLines.add(resultStrings) all over

  def fileName = "blahblah-${dateOrSomething}.csv"
  def dumbFile = new File('web-app/tmpfiles/'+fileName).withWriter {out ->
    lotsaLines.each{
      out.println it
    }
  }
  [fileName:fileName]
}

然后他们进入 gimmeAFile.gsp,该页面包含实际下载文件的链接:

<a href="${resource(dir:'tmpfiles',file:fileName)}">Download Report</a>

如何在列表查看器上创建一个链接,以便创建并下载文件,而不会将用户拖到额外的屏幕。注意:我不能预先生成文件,因此我需要想出如何链接到尚不存在的文件。我认为可以在控制器的末尾使用render()之类的东西。我能否让gimmeAFile控制器直接提供文件而不是创建一个带有文件链接的页面?
好的,为了澄清,这是我基于Kaleb的答案最终找到的解决方案。非常感谢!
def gimmeAFile = {
  def lotsaLines = []
  //Do a ton of stuff that has lotsaLines.add(resultStrings) all over

  def fileName = "blahblah-${dateOrSomething}.csv"
  def dumbFile = new File('web-app/tmpfiles/'+fileName).withWriter {out ->
    lotsaLines.each{
      out.println it
    }
  }
  def openAgain = new File('web-app/tmpfiles/'+fileName)
  response.setContentType("text/csv")
  response.setHeader("Content-disposition", "filename=${fileName}")
  response.outputStream << openAgain.getBytes()
  response.outputStream.flush()
  return
}
2个回答

3
您可以创建一个视图,只需获取文件的字节并将其写入响应即可:
response.contentType  = 'image/jpeg' // or whatever content type your resources are
response.outputStream << file.getBytes()
response.outputStream.flush()

您想要做的就是这个吗?


这应该是正确的轨迹,但如果我使用.getBytes(),我会得到错误:groovy.lang.MissingMethodException: No signature of method: java.util.ArrayList.getBytes() is applicable for argument types: () values: [],而如果我使用.bytes,文件就是垃圾。 - Mikey
1
好的。我需要以不同于使用.withWriter的对象重新打开文件,以便执行.getBytes()方法。 - Mikey
2
file.bytes 更加时髦! - rodvlopes

3

另一个更好的选择是,你可以直接从你的控制器操作中呈现文件:

render(file: theFile, contentType: 'your/contentType')

请参见:http://grails.org/doc/latest/ref/Controllers/render.html (我发现如果添加fileName选项,它会提示用户下载文件。)

能否使用它并仍然具有更新页面的其他更改的操作? 我猜,您能否在一个动作中执行两个渲染?一个用于文件,一个用于页面? - Joseph Nelson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接