Grails:在 gsp 中显示创建的图像

Posted

技术标签:

【中文标题】Grails:在 gsp 中显示创建的图像【英文标题】:Grails: displaying created image in gsp 【发布时间】:2011-05-28 23:40:26 【问题描述】:

我对 Grails 很陌生,所以这个问题可能有一个非常简单的答案。我正在尝试在 gsp 中显示动态创建的图像。图像不存储在数据库中,它是在控制器中动态创建的。

我基本上拥有的是一个 gsp,它具有一个接受一组用户输入的表单 (requestGraph.gsp)。提交表单后,参数被发送到控制器中的 displayGraph 操作,该操作从完全在 Grails 之外的数据库中查询信息,并使用 JFreeChart 库创建图表。我想在 displayGraph.gsp 或类似的东西中显示这个图像。

所以基本上在 requestGraph.gsp 中我有一个类似于:

<g:form action="displayGraph">
    <!-- ... bunch of labels and boxes -->
    <g:submitButton name="displayGraph" value="Display Graph" />
</g:form>

在控制器中我有类似的东西:

def requestGraph = 

def displayGraph = 
    //... code that uses params  to make an image byte array and assigns to var img
    return [image : img]

在 displayGraph.gsp 中:

<body>
    <h1>Graph Title</h1>
    <!-- ??? How to dislpay image? -->
</body>

我尝试将图像直接传送到 displayGraph 操作中的输出流。这可行,但随后我失去了对 displayGraph.gsp 中所有页面格式的控制。

我发现的大多数教程都创建了一个专门的操作来将图像传输到输出流,然后使用标签调用该操作。问题是我的图像没有存储在数据库中,而且我看不到传递图像字节数组(甚至是表单参数)来创建/渲染图像的方法。有人可以帮我吗?谢谢。

【问题讨论】:

【参考方案1】:

如果您将字节写入输出流,您可以将控制器/动作视为 GSP 中图像的来源。这是一个未经测试的快速示例:

// controller action
def displayGraph = 
    def img // byte array
    //...
    response.setHeader('Content-length', img.length)
    response.contentType = 'image/png' // or the appropriate image content type
    response.outputStream << img
    response.outputStream.flush()

然后您可以在&lt;img&gt; 标签的src 中访问您的图像,如下所示:

<img src="$createLink(controller: 'myController', action: 'displayGraph')"/>

更新

再次阅读您的问题后,这可能有效,也可能无效 - 看起来您可能会将图表显示为表单提交的结果。这仅在您将状态存储在服务器上某处的情况下才有效(而不是仅从提交表单的一个请求中获取它)。如果您确实在服务器上存储了足够的状态来生成图形,那么您必须向控制器提供一些额外的参数才能获得正确的图像,例如src="$g.link(controller: 'myController', action: 'displayGraph', params: ['id': 1234])",其中 id 是您检索图形状态的方式。

【讨论】:

我试过了。我发现当我将图像直接写入输出流时,它会立即以图像而不是网页的形式显示在浏览器中。当然,这意味着我不能向页面添加任何类型的格式或逻辑。 如果您在浏览器中直接访问myController/displayGraph,就会发生这种情况;但如果您将其用作图像的src,您仍然拥有页面控制权。但是,我刚刚更新了我的答案,其中的规定可能仍会妨碍您。 这是正确的做法。但我建议您将图像和其他文件保存在文件系统中,并仅存储在 db 路径和类型中。附言如果你想要调整图像大小的代码(这在我的项目中很有用),问我。 谢谢。我最终将表单中的所有参数聚合到一个命令对象中,并将其存储在 Flash 范围内。然后,我使用 Rob 的方法链接到 gsp 中的一个操作,该操作将检索命令对象并创建图像。感觉有点hacky,但它有效。 对我来说,reponse.outputStream &lt;&lt; img 不起作用。我不得不说:response.outputStream.write(img) - 只是提醒其他有这个问题的人【参考方案2】:

我相信这不是关于 Grails,而是关于 html。你可以:

    使管道图像的专用动作接受某些参数,并在该动作中生成图像;

    将 base64 编码嵌入到 HTML 中,例如 here:

【讨论】:

这可能是最优雅的答案,因为现在大多数浏览器都支持这个。但是,如果他必须支持 IE7,那就不行了。【参考方案3】:

我的建议实际上有两个部分。

1) 使用上面 Rob 推荐的解决方案生成图表工件,但是将其保存到具有唯一标识符的静态文件,该标识符作为表单提交响应的一部分传回,然后渲染图表与渲染任何其他图像没有什么不同。

我建议从表单提交中传递的特定参数构造标识符,以便它们可以用作缓存机制来再次呈现图表而无需重建它

2) 创建一个服务,可能是Quartz Service,它会定期清理为应用程序创建的静态图表

【讨论】:

【参考方案4】:

以下代码适用于 Grails 2.x。

HomeController.groovy

class HomeController 

    def index() 
    


    def viewImage()
        def file = new File(params.title)
        def img = file.bytes
        response.contentType = 'image/png' // or the appropriate image content type
        response.outputStream << img
        response.outputStream.flush()
    

views/home/index.jsp

<%@ page contentType="text/html;charset=ISO-8859-1" %>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
    <meta name="layout" content="main"/>
    <title>View Image</title>
</head>
<body>
  <div class="body">
  <img src="<g:createLink controller="home" action="viewImage"
          params="[title: 'C:/pictures/myimage.png']"/>"/>
  </div>
</body>
</html>

【讨论】:

【参考方案5】:

只是对@Rob 答案的改进:

另一个更好的选项,您可以直接从控制器的操作中渲染图像:

// controller action
def displayGraph = 
    def img // a byte[], File or InputStream
    render(file: img, contentType: 'image/png')

另请参阅:http://grails.org/doc/latest/ref/Controllers/render.html

【讨论】:

【参考方案6】:

由于任何原因,上述解决方案不显示任何图像。我用过:

<img src='$createLink(controller: "myController", action: "displayGraph")' />

改为。

【讨论】:

【参考方案7】:

我使用 FileUploadService 将图像文件保存在 Grails 中。如果您从目录获取图像意味着,请尝试以下操作:

<img style="height: 120px;width: 102px;"src="$resource(dir:'personImages', file:    personalDetailsInstance.id + '.png')" />

【讨论】:

【参考方案8】:

您的 gsp:

<img src="$createLink(controller: "image", action: "draw")" />

你的控制器:

def draw() 
  byte[] imageInBytes = imageService.getImageInBytes() //should return byte array 

  response.with
    setHeader('Content-length', imageInBytes.length.toString())
    contentType = 'image/jpg' // or the appropriate image content type
    outputStream << imageInBytes
    outputStream.flush()
  

【讨论】:

以上是关于Grails:在 gsp 中显示创建的图像的主要内容,如果未能解决你的问题,请参考以下文章

在 GSP 中打印时在变量中评估 Groovy/Grails 代码

Grails - 简单的 hasMany 问题 - 在 create.gsp 中使用 CheckBoxes 而不是 HTML Select

带有 Spring Security Core 的 Grails 仅允许所有者在 GSP 中更新

如何从 gsp 调用 Grails 服务?

Grails Spring Security 插件和 GSP 标签不起作用

Grails 在 javascript 内的 GSP 站点中使用 grails var