跨控制器操作的文件上载对象

时间:2014-10-20 15:47:10

标签: grails file-upload

运行Grails 2.3.3并且我有一个多文件输入要求,需要将所选文件对象从一个动作转移到另一个动作 - 第一个动作从多个'input'标记捕获文件列表。该数据通过'params'发送到第二个动作。通过params,我可以在第二个动作中访问文件对象的字符串表示。

我使用定义明确地将它们转换为MultipartFile类型的列表:

def <MultpartFile> []

然后将每个文件对象放入列表中。

当我打印出文件对象时,它们以以下形式显示:

org.springframework.web.multipart.commons.CommonsMultipartFile@25af2936

这与第1次动作显示的相同。

但是当试图在第二个动作中使用对象的元素时,例如file.originalFilename,我得到一个MissingPropertyException错误:

  

没有这样的属性:类的getOriginalFilename:java.lang.String

是否有办法将此字符串转换为适当的类型以进行文件传输,因为最终我希望能够从第2个操作传输(上传)所选文件。或者是否需要在使用多文件输入标记链接到视图的原始操作中进行任何文件传输?

FUTHER EXPLANATION:

我没有完全解释流逻辑。我不是直接从另一个动作调用一个动作,而是通过视图上的按钮来执行。在视图中,我从html多输入标记获取一组文件,然后从视图中转到“保存”操作submitButton此操作创建另一个显示这些选定文件的视图,并允许用户添加一些额外的描述性标记。在此保存视图中,有另一个提交按钮进入上传操作,该操作意味着收集所有这些文件信息并上传文件(利用每个文件的MultipartFile对象进行文件传输)以及用户提供的其他数据。

-Mike

1 个答案:

答案 0 :(得分:1)

这不是它的工作原理 - 你几乎从不希望一个控制器动作调用另一个。并且您无法将params的全部内容打包到查询字符串中以进行重定向。对于初学者来说,查询字符串的大小是有限制的(我不知道它是什么,我不在乎 - 我不希望接近极限),所以如果你有一个文件不是很小,你会在重定向中失去大部分。您也不能只将任何旧的数据类型转储到查询字符串中 - 您需要以允许您在不丢失的情况下反序列化的格式进行序列化,并且简单的toString()调用几乎不是那种格式,除了麻木,布尔和字符串。

控制器由Grails和处理请求的Spring MVC代码调用。如果要在一个请求期间从两个控制器操作执行工作,则将非HTTP代码提取到另一个未像控制器操作那样间接调用的类,例如,服务。

我立即将持久性和业务逻辑重构为服务 - 控制器应该是愚蠢的路由器;他们处理请求,对查询字符串args和表单正文数据进行一些数据绑定,确定要调用哪个帮助程序来执行此操作(可能是服务和/或域类),然后在调用时调用帮助程序完成,转换到下一页(使用重定向或转发)或呈现响应。

数据以事务方式编写也非常重要,默认情况下服务是事务性的,因此它们是该代码的理想之地。忽略Grails 2.3和2.4控制器中的@Transactional注释 - 它们使代码稍微好一些,但它仍然完全在错误的位置。

即使你没有立即重构你的控制器,一旦它的方法变得有点大,或者它们有太多的方法(或多个相关的动作组,并且每个都应该有自己的控制器) ,或者你做数据库写和业务逻辑。这可能听起来像你工作的每个应用程序中的每个控制器 - 我们需要做得更好,让Grails开发人员不要像PHP开发人员一样思考,在任何方便的地方倾倒东西,或者代码生成脚本似乎暗示事情发生的地方

因此,为了满足您的特定需求,请将这两个控制器重构为两个(或更多,如果有意义)服务中的方法。从第一个控制器操作中提取文件上载数据并执行与现在相同的工作,但是在服务中而不是控制器中。这个服务方法可以根据需要调用许多其他方法,并且永远不会像HTTP重定向一样笨拙 - 只是一个普通的旧方法调用。

最后一件事 - 就像数据库写入和业务逻辑不属于控制器一样,您同样不希望服务层知道HTTP。这意味着不要将请求,响应,会话甚至params传递给服务方法。从中获取所需的数据并在方法签名中使用它。您不可能独立于控制器,标记库,域类等重用服务类,如果不连接层,则可以。如果你将特定于HTTP的代码保留在sruvices之外,它们将变得更加便携,并且更容易测试,因为在获得你要验证的内容方面存在较少的垃圾。