Reporting errors from the application services lay

2019-09-02 18:47发布

I'm implementing web application based on Spring MVC and organized around DDD concepts. Currently I try to implement ticket reservation functionality. The customer can see number of tickets available for the particular event. Then, he can enter number of tickets to be reserved and submit form. Request is received by controller which calls application service responsible for registration. Application service logic is as follows:

  1. Validate incoming parameters:
    • 1A. Check if event with the given ID exists
    • 1B. Check if number of tickets available allows for reservation
  2. If validation passed, proceed with registration; otherwise, report an error.

I have some doubts about the proper way for reporting validation errors - especially for point 1B. Situation when number of tickets does not allow for reservation is not something very unusual. Customer can see number of tickets that is not fully synchronized with current number of tickets in database (eventual consistency) - some other person could reserve some tickets in the meantime.

Initially I was thinking about reporting this problems by throwing some specific exceptions. However, I can think of couple of other problematic situations and having one exception for each on of them doesn't sound very well.

The other option I was considering was throwing one type of exception containing error code. However, I don't know how to handle this situation in Spring MVC properly.

What are the best practices for such problems? How do you deal with them in your MVC applications? Any advices greatly appreciated.

1条回答
我命由我不由天
2楼-- · 2019-09-02 19:11

I think these are business constraint brokens that cannot be recovered.

My current solution is Exception hierachy.

public abstract class UncheckedApplicationException extends RuntimeException {

    //omitted factory methods and constructors
    public abstract String getStatusCode();

    public abstract String getI18nCode();//ignore this if you don't need i18n    

    public abstract String[] getI18nArgs();//ignore this if you don't need i18n 
}

Any custom exception extends this one. I think this could avoid code like this:

try {  
    //invoke your application service
} catch (InsufficientInventoryException e) {  
    statusCode = INSUFFICIENT_INVENTORY;  
} catch (ExpriedPriceException e) {  
    statusCode = EXPIRED_PRICE;  
} catch (NoSuchProductException e) {  
    statusCode = NO_SUCH_PRODUCT;  
} catch (Exception e) {  
    statusCode = UNKNOWN;  
}

Controller code snippet:

try {  
    //invoke your application service here 
    statusCode = SUCCESS;
    message = messageSource.getSuccess(locale));
} catch (UncheckedApplicationException e) {  
    statusCode = e.getStatusCode();  
    message = messageSource.getMessage(e, locale));
} catch (Exception e) {  
    statusCode = UNKNOWN;  
    message = messageSource.getUnknownError(e, locale));
}
//add statusCode & message to modelAttribute

You can use @ExceptionHandler to reduce boilerplate try-catch code if your Controller is well organized(but pretty difficult).

The other reason to use Excepton is that application service is often used to delimit transaction boundary. An exception has to be thrown if you want to rollback.

查看更多
登录 后发表回答