Grails使控制器很容易调用服务,控制器可以将请求转发到另一个控制器上。
假设您有这样的服务方法
List<String> updateNames() {
...
}
您可以从任何控制器轻松调用它。
我很想知道,如果你有一个边缘情况,你会发现你的服务方法存在验证问题。你不想把一个Exception抛回你的控制器,因为它并不是一个特例。但是你不能将服务中的错误消息返回给调用的Controller,因为这意味着你必须使用一些包装器对象而不是一个好的List
无论如何,对于这些情况,您可以让服务器将服务器端转发到另一个可能会向用户返回错误响应的Controller吗?
感谢。
答案 0 :(得分:2)
Grails已经有了一个在bean中进行验证的结构,称为Errors(来自Spring)。例如,如果您有上传文件的服务,则可以在bean中轻松附加验证错误:
class UploadService {
void doUpload(MultipartFile file, MyDomainClass domainClassInstance) {
if(validationsFail) {
domainClassInstance.errors.rejectValue("myUploadField","my.i18n.code")
}
}
}
如果它不是域类,您可以考虑使用command object,因为它们也是可验证的。
在你的控制器中,它只是检查你的实例是否有错误:
def upload() {
MyDomainClass instance = ...
uploadService.doUpload(request.getFile('file'), instance)
if(!instance.hasErrors()) {
//save and go on...
}
}
另一个选择是使用@Joshua Moore回答的例外情况。请记住延长RuntimeException
。如果不这样做,您的交易将不会自动回滚。
答案 1 :(得分:1)
服务不会以这种方式知道web / http请求上下文。我不会深入了解这一行如何通过会话或请求作用域服务模糊,因为它仍然不适用于您所询问的内容。此外,您真的不希望您的服务甚至意识到它正在处理web / http请求,因为您想要分离职责并拥有良好/干净的设计。
所以,回到你的问题。这正是从服务中引发异常并让控制器处理该异常结果的情况。如果它是实例上的验证错误,那么您应该能够访问控制器中实例的错误集合(当然,前提是它是您服务的输入)。
作为关于服务例外的附注。填充堆栈的痕迹很昂贵。在Grails中更是如此,因为有很多工作正在进行中。我强烈建议您从服务中提出自己的业务逻辑异常,并在异常时覆盖fillInStackTrace方法以避免此成本。
以下是一个例子:
package com.example
class MyBusinessException extends RuntimeException {
List<String> argList = []
public MyBusinessException (String message, List<String> args){
super(message)
argList = args
}
public MyBusinessException (String message){
super(message)
}
/**
* Don't fill in the stack trace because we want things to be faster.
**/
@Override
public Throwable fillInStackTrace() {
// do nothing
return this
}
}