如何在Grails GSP中显示图片?

9

我还在学习Grails,看起来遇到了一个难题。

以下是两个领域类:

class Photo {
    byte[] file 

    static belongsTo = Profile
}


class Profile {
    String fullName
    Set photos

    static hasMany = [photos:Photo]     
}

相关控制器代码片段:

class PhotoController {

    def viewImage = {

      def photo = Photo.get( params.id )
      byte[] image = photo.file 
      response.outputStream << image

    } 
} 

最后是GSP代码片段:

<img class="Photo" src="${createLink(controller:'photo', action:'viewImage', id:'profileInstance.photos.get(1).id')}" />

现在我该如何访问照片,以便它显示在GSP上?我相当确定profileInstance.photos.get(1).id是不正确的。


你试过这个吗?它应该会调用'viewImage',并将id设置为1,引用一个Photo实例,假设在作用域中有'profileInstance'。你可能需要调整响应内容类型。你是在问如何选择显示哪张照片吗? - Ken Gentle
我希望能够显示集合中的第一张照片,谢谢。 - Kevin
6个回答

4
如果您有图片的url,只需确保在控制器中返回适当的答案即可:
  def viewImage= {
    //retrieve photo code here
    response.setHeader("Content-disposition", "attachment; filename=${photo.name}")
    response.contentType = photo.fileType //'image/jpeg' will do too
    response.outputStream << photo.file //'myphoto.jpg' will do too
    response.outputStream.flush()
    return;
  }

3

由于它是一个集合,如果你想要第一个元素,你需要执行以下操作:

profileInstance.photos.toArray()[0].id

或者

profileInstance.photos.iterator().next()

是的,/photo/viewImage/{anyPhotoId} 能正确显示照片。实际上,我想我使用了 Set 而不是 ArrayList。这是问题的原因吗?谢谢! - Kevin
@Walter - 啊,是的。我已经修改了我的答案。 - Hates_

2

现在,我认为将照片作为二进制大对象存储在数据库中并不是最佳解决方案 - 尽管您可能有需要这样做的原因。

那么,将照片的名称(和/或路径)存储起来怎么样?如果存在名称冲突问题,则使用照片的md5校验和作为名称。然后,照片变成了一个静态资源,一个简单的文件,而不是一个更复杂和更慢的MVC请求。


这可能是一个选项。我需要进一步探索它。谢谢! - Kevin
1
那么如何保护这个图片呢?如果你使用直接的文件URL,你就失去了将图片保护给特定用户/角色的能力(或者使其变得更加困难)。 - billjamesdev
@bill:我想这取决于需求。安全性是有代价的,而我的方法在安全方面有点困难(不是不可能,但如果安全很重要的话,使用其他人的建议可能更简单)。 - Chii
1
除了安全性之外,还可以提到您会变得容易受到“文件系统问题”的影响(例如在某个环境中托管,别人可以删除您的文件)。此外,如果您将 blob 存储在数据库中,您可以将其封装在一个类中,该类可以存储其他元数据,您可以使用这些元数据执行各种有趣的操作,例如“查找所有猫的图片”,这在文件系统存储中很难实现。虽然性能很重要,但在关系型环境中存储文件的原因有很多。 - Visionary Software Solutions
将东西存储在文件系统中也会使备份/恢复、导出等变得更加复杂,并增加额外的基础架构复杂性和配置。此外,如果您正在使用动态CDN(如Akamai),则从数据库加载图像的额外开销对于缓存请求不会成为问题。我使用从数据库加载的图像构建了一个CMS,性能影响并不明显。 - Ken Liu

1

我也在学习Grails,一直在寻找这样的示例。GSP代码片段对我不起作用,但我通过替换profileInstance.photos.get(1).id周围的单引号来解决了问题。

<img class="Photo" src="${createLink(controller:'photo', action:'viewImage', id:'profileInstance.photos.get(1).id')}" />

带双引号:

<img class="Photo" src="${createLink(controller:'photo', action:'viewImage', id:"profileInstance.photos.get(1).id")}" />

现在Grails会解析双引号周围的表达式,否则它会将其视为字符串。


0

id:'profileInstance.photos.get(1).id' 应该是 id:profileInstance.photos.get(1).id。没有限额。


0

我猜你需要设置响应流的内容类型。类似这样:

response.ContentType = "image/jpeg"

这可能需要在您将流式传输到响应流之前完成,也可能不需要(无法想象它会有什么影响)。我只会在您上面代码中的outputStream行之前放置它。


我测试了一下,似乎不需要设置内容类型。谢谢。 - Kevin

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