将Groovy和Grails惯用的方式转换为域模型类是什么?

将Groovy和Grails惯用的方式转换为域模型类是什么?,grails,groovy,Grails,Groovy,考虑到Grails域类“Apple.groovy”和“Orange.groovy”没有严格的关联,以及从控制器调用的以下Grails服务: package test import grails.transaction.Transactional import javax.servlet.http.HttpServletRequest @Transactional class UploadService { def uploadApple(HttpServletRequest re

考虑到Grails域类“Apple.groovy”和“Orange.groovy”没有严格的关联,以及从控制器调用的以下Grails服务:

package test

import grails.transaction.Transactional

import javax.servlet.http.HttpServletRequest

@Transactional
class UploadService {

    def uploadApple(HttpServletRequest request, Apple o) {
        def file = request.getFile('payload')
        o.payload = file.getBytes()
        o.filename = file.originalFilename
        o.contentType = file.contentType
        o.save(flush:true)
    }

    def uploadOrange(HttpServletRequest request, Orange o) {
        def file = request.getFile('payload')
        o.payload = file.getBytes()
        o.filename = file.originalFilename
        o.contentType = file.contentType
        o.save(flush:true)
    }

}
如何用一种通用的方法来统一这段代码?我希望Groovy的可选类型能够为我处理这个问题,但是如果我从方法签名中删除类型,我似乎无法成功地调用
.save()


提前感谢

避免将
请求
传递给服务,并将
文件
传递给服务。你是这样试的吗

def upload(file, obj) {
        obj.payload = file.getBytes()
        obj.filename = file.originalFilename
        obj.contentType = file.contentType
        obj.save(flush:true)
}
与Java不同,Groovy不进行duck类型化。键入涉及将类型指定给任何对象。Duck类型涉及确定对象是否适合某些用途

现在,您必须小心,因为这不会适用于所有对象。它适用于
Apple
Orange
的原因是它们都具有完全相同的属性集和属性类型


有人会想,为什么会有两个行为完全相同的不同域,但这显然是一个不同的讨论

避免将
请求
传递给服务,并将
文件
传递给服务。你是这样试的吗

def upload(file, obj) {
        obj.payload = file.getBytes()
        obj.filename = file.originalFilename
        obj.contentType = file.contentType
        obj.save(flush:true)
}
与Java不同,Groovy不进行duck类型化。键入涉及将类型指定给任何对象。Duck类型涉及确定对象是否适合某些用途

现在,您必须小心,因为这不会适用于所有对象。它适用于
Apple
Orange
的原因是它们都具有完全相同的属性集和属性类型


有人会想,为什么会有两个行为完全相同的不同域,但这显然是一个不同的讨论

在Grails3中,域类实现了trait,这就是
save()
方法的来源。但这并不能解决
有效负载
文件名
内容类型
属性的问题

您可以做的是创建一个接口,该接口声明两个域类通用的方法和属性,并实现
org.grails.datastore.gorm.GormEntity
。然后,让域类实现接口:

interface Uploadable extends GormEntity {
    byte [] payload
    String filename
    String contentType
}

class Apple implements Uploadable {
    byte [] payload
    String filename
    String contentType
}
然后,您可以在服务中使用该接口

@Transactional
class UploadService {

    def upload(HttpServletRequest request, Uploadable o) {
        def file = request.getFile('payload')
        o.payload = file.getBytes()
        o.filename = file.originalFilename
        o.contentType = file.contentType
        o.save(flush:true)
    }

}

注意:由于Grails自动将
GormEntity
特性注入域类,因此我不知道如果如图所示显式使用它会发生什么情况。

在Grails 3中,域类实现该特性,这就是
save()
方法的来源。但这并不能解决
有效负载
文件名
内容类型
属性的问题

您可以做的是创建一个接口,该接口声明两个域类通用的方法和属性,并实现
org.grails.datastore.gorm.GormEntity
。然后,让域类实现接口:

interface Uploadable extends GormEntity {
    byte [] payload
    String filename
    String contentType
}

class Apple implements Uploadable {
    byte [] payload
    String filename
    String contentType
}
然后,您可以在服务中使用该接口

@Transactional
class UploadService {

    def upload(HttpServletRequest request, Uploadable o) {
        def file = request.getFile('payload')
        o.payload = file.getBytes()
        o.filename = file.originalFilename
        o.contentType = file.contentType
        o.save(flush:true)
    }

}

注意:由于Grails将
GormEntity
特性自动注入到域类中,我不知道如果如图所示显式使用它会发生什么。

aaik,save()作为元类扩展实现。类型是否在方法签名中声明并不重要。您看到的错误是什么?
错误500:内部服务器错误URI/Apple/save Class java.lang.NoSuchMethodError消息处理程序处理失败;嵌套的异常是java.lang.NoSuchMethodError:UploadService。u执行([Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;由UploadService引起。u执行([Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;
您的
u执行()
?不知道如何检查,这是grails create service Upload所生成的
generates.aaik,save()作为元类扩展实现。无论类型是否在方法签名中声明。您看到的错误是什么?
error 500:内部服务器错误URI/Apple/save Class java.lang.NoSuchMethodError消息处理程序处理失败;嵌套异常为java.lang.NoSuchMethodError:UploadService。\u执行([Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;由UploadService引起。u execute([Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;
您的
\uu execute()是什么
?不确定如何检查,它是由
grails create service Upload
生成的。如果您还没有使用
文件
s,但是使用
HttpServletRequest
s,您将从请求中获取文件,那么您可以在控制器中调用该服务:
uploadService、 上传(request.getFile('payload'),苹果)
对于orange,您显然会通过
orange
。但是在您将文件传递到服务之前,请确保它不是null或验证它。令人惊讶的是,它工作得如此之好。我不清楚为什么这会起作用,我的初始方法不会。是否愿意详细说明?谢谢。我会将其添加到我的答案中。您将如何从控制器调用它r如果您还没有使用
文件
s,但是使用
HttpServletRequest
s,那么您将从请求中获取文件。因此,在控制器中,您可以这样调用服务:
uploadService.upload(request.getFile('payload'),apple)
对于orange,您显然会通过
orange
。但是在您将文件传递到服务之前,请确保它不是null或验证它。令人惊讶的是,它工作得如此之好。我不清楚为什么这会起作用,我最初的方法不会。是否愿意详细说明?谢谢。我会将其添加到我的答案中。感谢您提供的信息性回复;决定接受另一个答案,因为它感觉更地道,尽管来自Java背景