Grails - 命令对象、服务方法
Grails - Command object, service method
我不是一个精通编程的人,所以请多多包涵。
我已阅读有关命令对象的博客条目和文档。我从未使用过它,想知道我是否应该使用它。 (我可能应该...)
我的项目需要在用户上传文件时解析、排序、计算并将结果保存到数据库中。
因此根据 blog entries I read and its corresponding github code、
之一
1) SERVICE
应该接收文件上传,解析上传的文件(主要是docs和pdfs),使用RegEx对解析的数据进行排序,并计算数据,
2) COMMAND OBJECT
应该调用 SERVICE
,收集结果并将结果发送回控制器,并将结果保存到数据库中,
3) CONTROLLER
应接收来自 VIEW
的请求,从 COMMAND OBJECT
获取结果,并将结果发送回 VIEW
。
我的理解正确吗?
谢谢。
是的,除了一件事,您理解正确:命令对象不应该将数据保存到数据库 - 让服务来做。命令对象的另一个优点是来自客户端的数据绑定和验证。在此处阅读有关命令对象的更多信息 grails command object docs
您还可以在本文中找到有关您的问题的有用信息
grails best practices
我发现这是最好的设置。这是我在生产中使用的示例:
命令对象(携带数据并确保其有效性):
@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])
}
}
我猜不是。它与保存是否在服务中完成并没有真正的关系,它应该总是尝试在服务中执行复杂的东西,特别是数据库的东西。所以这无关紧要。我倾向于不使用命令对象,但已经迷上了助手 classes aka beans,它位于 src/main/groovy 中并进行所有验证和格式化。我刚刚做了一个表格,里面有反馈和理由。
最初我以为我会逃脱
def someAction(字符串反馈,字符串原因){
someService.doSomething(反馈,原因)
}
但后来我看起来很封闭,我的表单首先是一个文本区域,然后选择对象是字节,所以上面没有工作,只是简单地修复它而不增加我的复杂性 controller/service 我这样做了:
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') {
.....
}
}
所有这些验证仍然必须在某个地方完成,你说没有验证但在一个好的模型中你应该进行验证并将东西存储在适当的结构中以减少随着时间的推移你的数据库过载。很难解释,但简而言之,我在谈论你的域 class 对象并确保你没有设置 String something string somethingelse 然后甚至没有定义它们的长度等。要严格并验证
如果你有一个文本区域,它将被存储在后端 - 所以你需要像上面那样 trim 它 - 你需要确保输入不超过实际的最大字符db 结构如果没有定义可能是 255
并通过
static constraints = {
user(nullable: true)
reason(min:1, max:255, nullable:true, inList:UsersRemoved.REASONS)
如果用户以某种方式超出了我的前端检查并输入了超过 255,则已经通过控制器中的 bean.validate() 使它无效。
这东西需要时间耐心等待
编辑以最终在该示例字节中添加 - 是一个需要注意的 -
当添加任何字符串或任何东西时,我已经开始像这样定义特定的,在字节的情况下,如果它是布尔值 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,我认为这是声明的字符串的默认值。
我不是一个精通编程的人,所以请多多包涵。
我已阅读有关命令对象的博客条目和文档。我从未使用过它,想知道我是否应该使用它。 (我可能应该...)
我的项目需要在用户上传文件时解析、排序、计算并将结果保存到数据库中。
因此根据 blog entries I read and its corresponding github code、
之一1) SERVICE
应该接收文件上传,解析上传的文件(主要是docs和pdfs),使用RegEx对解析的数据进行排序,并计算数据,
2) COMMAND OBJECT
应该调用 SERVICE
,收集结果并将结果发送回控制器,并将结果保存到数据库中,
3) CONTROLLER
应接收来自 VIEW
的请求,从 COMMAND OBJECT
获取结果,并将结果发送回 VIEW
。
我的理解正确吗?
谢谢。
是的,除了一件事,您理解正确:命令对象不应该将数据保存到数据库 - 让服务来做。命令对象的另一个优点是来自客户端的数据绑定和验证。在此处阅读有关命令对象的更多信息 grails command object docs 您还可以在本文中找到有关您的问题的有用信息 grails best practices
我发现这是最好的设置。这是我在生产中使用的示例:
命令对象(携带数据并确保其有效性):
@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])
}
}
我猜不是。它与保存是否在服务中完成并没有真正的关系,它应该总是尝试在服务中执行复杂的东西,特别是数据库的东西。所以这无关紧要。我倾向于不使用命令对象,但已经迷上了助手 classes aka beans,它位于 src/main/groovy 中并进行所有验证和格式化。我刚刚做了一个表格,里面有反馈和理由。
最初我以为我会逃脱
def someAction(字符串反馈,字符串原因){ someService.doSomething(反馈,原因) }
但后来我看起来很封闭,我的表单首先是一个文本区域,然后选择对象是字节,所以上面没有工作,只是简单地修复它而不增加我的复杂性 controller/service 我这样做了:
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') {
.....
}
}
所有这些验证仍然必须在某个地方完成,你说没有验证但在一个好的模型中你应该进行验证并将东西存储在适当的结构中以减少随着时间的推移你的数据库过载。很难解释,但简而言之,我在谈论你的域 class 对象并确保你没有设置 String something string somethingelse 然后甚至没有定义它们的长度等。要严格并验证
如果你有一个文本区域,它将被存储在后端 - 所以你需要像上面那样 trim 它 - 你需要确保输入不超过实际的最大字符db 结构如果没有定义可能是 255
并通过
static constraints = {
user(nullable: true)
reason(min:1, max:255, nullable:true, inList:UsersRemoved.REASONS)
如果用户以某种方式超出了我的前端检查并输入了超过 255,则已经通过控制器中的 bean.validate() 使它无效。
这东西需要时间耐心等待
编辑以最终在该示例字节中添加 - 是一个需要注意的 -
当添加任何字符串或任何东西时,我已经开始像这样定义特定的,在字节的情况下,如果它是布尔值 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,我认为这是声明的字符串的默认值。