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

Grails 跨控制器操作文件上载对象,grails,file-upload,Grails,File Upload,运行Grails 2.3.3和我有一个多文件输入需求,需要将选定的文件对象从一个操作转移到另一个操作——第一个操作从多个“输入”标记捕获文件列表。此数据通过“参数”发送到第二个操作。通过params,我可以访问第二个操作中文件对象的字符串表示形式 在这里,我使用以下定义将它们显式转换为类型MultipartFile的列表: def <MultpartFile> [] def[] 然后将每个文件对象放入列表中 当我打印出文件对象时,它们将显示在表单中: org.springfram

运行Grails 2.3.3和我有一个多文件输入需求,需要将选定的文件对象从一个操作转移到另一个操作——第一个操作从多个“输入”标记捕获文件列表。此数据通过“参数”发送到第二个操作。通过params,我可以访问第二个操作中文件对象的字符串表示形式

在这里,我使用以下定义将它们显式转换为类型MultipartFile的列表:

def <MultpartFile> []
def[]
然后将每个文件对象放入列表中

当我打印出文件对象时,它们将显示在表单中:

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

这与第一个动作显示的相同

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

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

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

进一步解释:

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


-mike

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

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

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

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

即使您不立即重构控制器,也应该在其方法变得有点大,或者它们有太多的方法(或者多组相关的操作,每个操作都应该有自己的控制器),或者您进行数据库写入和业务逻辑时立即重构控制器。这可能听起来像是您所使用的每个应用程序中的每个控制器——我们需要做得更好,让Grails开发人员不要像PHP开发人员那样思考,在方便的地方转储内容,或者在代码生成脚本似乎暗示的地方转储内容

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


最后一件事——就像数据库写入和业务逻辑不属于controollers一样,您同样不希望服务层了解HTTP。这意味着不要将请求、响应、会话甚至参数传递给服务方法。从它们中提取出您需要的数据,并在方法签名中使用这些数据。您不太可能独立于控制器、标记库、域类等重用服务类,如果您不耦合层,您可以这样做。如果您不让特定于HTTP的代码进入s服务,它们将变得更具可移植性,也更易于测试,因为在获取您试图验证的内容的过程中,垃圾更少。

def[]
不是有效的Groovy-这应该代表什么?请参阅上面的进一步解释。我完全接受您关于将业务逻辑从控制器中取出并引入服务的建议,但对于应用程序来说,这似乎是一个相当自然的用户界面流。从您所说的情况来看,可能还有其他问题,例如通过从一个操作到另一个操作的参数传输,“丢失”文件对象的详细信息。此外,文件的数量可能是开放的,这可能会导致问题。所有迹象都指向通过js和ajax在单个视图中完成所有这一切