2014-04-16 43 views
0

Grails使控制器可以很容易地調用服務,並使控制器可以將請求轉發到另一個控制器。服務調用回控制器?

所以假設你有一個服務方法等

List<String> updateNames() { 
    ... 
} 

你可以很容易的把它從任何控制器。

我想知道,如果你有一個邊緣情況,你意識到你的服務方法有驗證問題。你不想把異常拋回到你的控制器中,因爲它不是一個特例。但是你不能從你的服務返回一個錯誤消息到被調用的Controller,因爲這意味着你必須使用一些包裝對象而不是一個好的列表

有沒有反正這些情況下,你可以得到服務做一個服務器端轉發到另一個控制器,它可能會返回一個錯誤響應給用戶?

謝謝。

+1

這對我來說似乎是一個例外的理想用例... –

+0

同意Sèrgio和Joshua。所有驗證異常都可以在使用命令對象或域實例本身進入服務類之前進行處理。正如約書亞提到關於分離問題,服務不應該知道http調用或任何驗證問題。它應該關心業務異常/場景。話雖如此,拋出運行時異常或服務錯誤將是我會做回滾事務的最後一件事。我們應該使用['TransactionAspectSupport'](http://stackoverflow.com/a/17357547/2051952)來處理回滾。 – dmahapatro

+0

@Ian Roberts爲什麼?這是您期望可能發生的情況,用戶可能會輸入錯誤的數據。你的系統本身沒有任何問題。 –

回答

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 
    } 
} 
2

的Grails已經有了用於驗證的結構,你的bean,稱爲Errors(表格正在添加春季)。舉例來說,如果你有一個服務上傳文件,你可以很容易地連接在Bean驗證錯誤:

class UploadService { 
    void doUpload(MultipartFile file, MyDomainClass domainClassInstance) { 
    if(validationsFail) { 
     domainClassInstance.errors.rejectValue("myUploadField","my.i18n.code") 
    } 
    } 
} 

如果它不是一個領域類,你可以考慮使用command object因爲他們太validateable。

在您的控制器,它只是檢查的梅特如果您的實例有錯誤:

def upload() { 
    MyDomainClass instance = ... 
    uploadService.doUpload(request.getFile('file'), instance) 
    if(!instance.hasErrors()) { 
    //save and go on... 
    } 
} 

另一種選擇是一個像@Joshua摩爾例外回答工作。請記住延長RuntimeException。如果您不這樣做,您的交易將不會自動回滾。