0

我不是一个精通编程的人,所以请多多包涵。

我已阅读有关命令对象的博客条目和文档。我从来没有用过它,我想知道我是否应该。(我可能应该...)

我的项目需要在用户上传文件时进行解析、排序、计算并将结果保存到数据库中。

因此,根据我阅读的一篇博客文章及其相应的github 代码

1)SERVICE应该接收文件上传,解析上传的文件(主要是docs和pdfs),使用RegEx对解析后的数据进行排序,并计算数据,

2)COMMAND OBJECT应该调用SERVICE,收集结果并将结果发送回控制器,并将结果保存到数据库中,

3)CONTROLLER应该从 接收请求,从VIEW获取结果COMMAND OBJECT,然后将结果发送回VIEW

我理解正确吗?

谢谢。

4

3 回答 3

2

我发现这是最好的设置。这是我在生产中使用的示例:

命令对象(携带数据并确保其有效性):

@grails.validation.Validateable
    class SearchCommand implements Serializable {
    // search query
    String s
    // page
    Integer page

    static constraints = {
        s                   nullable: true
        page                nullable: true
    }

}

控制器(将请求定向到服务,然后从服务获取响应并将此响应定向到视图):

class SomeController {

    //inject service
    def someService

    def search(SearchCommand cmd) {
        def result = someService.search(cmd)
        // can access result in .gsp as ${result} or in other forms
        render(view: "someView", model: [result: result])
    }
}

服务(处理业务逻辑并从域中获取数据):

class SomeService {
    def search(SearchCommand cmd) {
        if(cmd.hasErrors()) {
            // errors found in cmd.errors
            return
        }
        // do some logic for example calc offset from cmd.page
        def result = Stuff.searchAll(cmd.s, offset, max)
        return result
    }
}

域(所有数据库查询都在这里处理):

class Stuff {
    String name
    static constraints = {
        name               nullable: false, blank: false, size: 1..30
    }

    static searchAll(String searchQuery, int offset, int max) {
        return Stuff.executeQuery("select s.name from Stuff s where s.name = :searchQuery ", [searchQuery: searchQuery, offset: offset, max:max])
    }
}
于 2016-04-14T17:44:36.540 回答
1

是的,你理解正确,除了一件事:命令对象不应该将数据保存到数据库 - 让服务来做到这一点。命令对象的另一个优点是数据绑定和来自客户端的数据验证。在此处阅读有关命令对象的更多信息grails command object docs 您还可以在本文 grails best practice中找到有关您的问题的有用信息

于 2016-04-14T16:54:15.450 回答
1

我猜不会。它与保存是否在服务中完成并没有真正的关系,它应该总是尝试执行复杂的东西,特别是服务中的数据库东西。所以不管怎样。我倾向于不使用命令对象,但已经迷上了位于 src/main/groovy 中并完成所有验证和格式化的辅助类(又名 bean)。我刚刚做了一个表格,里面有反馈和理由。

起初我以为我会侥幸逃脱

def someAction(String feedback, String reason) { someService.doSomething(feedback,reason) }

但是后来我看起来很封闭,​​我的表单首先是一个文本区域,然后选择对象是字节,所以上面的不起作用,为了简单地修复它而不增加我的控制器/服务的复杂性,我这样做了:

packe some.package
import grails.validation.Validateable

class SomeBean implements Validateable {

    User user

    byte reason
    String feedback

    static constraints = {
        user(nullable: true)
        reason(nullable:true, inList:UsersRemoved.REASONS)
        feedback(nullable:true)
    }

    void setReason(String t) {
        reason=t as byte
    }

    void setFeedback(String t) {
        feedback=t?.trim()
    }
}

现在我的控制器

class SomeController {
  def userService
  def someService
 def doSomething(SomeBean bean){
        bean.user = userService.currentUser
        if (!bean.validate()) {
 flash.message=bean.errors.allErrors.collect{g.message([error : it])}
            render view: '/someTemplate', model: [instance: bean,template:'/some/template']
            return
        }

        someService.doSomeThing(bean)
}
}

现在我的服务

Class SomeService {
def doSomeThing(SomeBean bean) {

if (bean.user=='A') { 
.....
}


}

所有这些验证仍然必须在某个地方完成,您说没有验证,但在一个好的模型中,您应该进行验证并将内容设置为存储在适当的结构中,以减少随着时间的推移使数据库过载。很难解释,但简而言之,我在谈论您的域类对象并确保您没有设置 String something string somethingelse 然后甚至不定义它们的长度等。严格并验证

如果你有一个文本区域,它将存储在后端 - 所以你需要像上面一样修剪它 - 你需要确保输入不超过实际 db 结构的最大字符,如果未定义,可能会是255

并通过做

  static constraints = {
            user(nullable: true)
            reason(min:1, max:255, nullable:true, inList:UsersRemoved.REASONS)

如果用户以某种方式超出了我的前端检查并输入超过 255,则已经通过控制器中的 bean.validate() 使其无效。

这东西需要时间耐心等待

编辑以最终添加该示例字节-要小心-

添加任何字符串或任何内容时,我已经开始定义像这样的特定内容,如果是 byte,如果它是布尔值 true false - 很好,如果不是,则将其定义为 tinyint

static mapping = {
 //since there is more than 1 type in this case
 reason(sqlType:'tinyint(1)')
 feedback(sqlType:'varchar(1000)')
// name(sqlType:'varchar(70)')
}

然后,如果您查看在数据库中创建的表,您应该会发现它们是根据定义创建的,而不是标准的 255 varchar,我认为这是声明字符串的默认值。

于 2016-04-14T21:12:37.277 回答