Изменить: Я просмотрел аннотацию Spring 3 @ExceptionHandler
, и объединение этого с вариантом 1 ниже выглядит довольно простым решением.
Я также нашел, что это хороший текст: http://blog.decaresystems.ie/index.php/2006/04/07/difficult-choices-in-handling-exceptions-in-enterprise-java-applications/
Я уже некоторое время разрабатываю с помощью среды Spring MVC, однако я изо всех сил стараюсь придумать "хороший" способ передать ошибки, поднятые в служебном слое обратно в JSP.
В принципе, я не считаю, что бизнес-логика (за исключением "это обязательное поле" ) должна быть в валидаторах, особенно в любой логике, требующей доступа к БД. Таким образом, то, что я делал, заключается в размещении на уровне обслуживания еще более сложной проверки и бизнес-логики.
Например, скажем, у меня есть страница, которая позволяет пользователю покупать книгу. Они нажимают "Купить" на JSP, и контроллер вызывает службу, чтобы все это произошло... Теперь, что произойдет, если служба увидит, что у них недостаточно средств - как я могу вернуть это сообщение в JSP, Сообщение "Недостаточно средств" может быть отображено пользователю? Я рассмотрел два пути, и я не уверен, что правильно...
Вариант 1: Исключения
Первый способ, по моему мнению, - создать исключение на уровне сервиса, запереть его в контроллере и добавить сообщение в BindingResult.
Услуги:
public void pay(Book book) throws InsufficientFundsException {
// Some logic goes here, which ends up throwing the above exception
}
Контроллер:
public ModelAndView(@ModelAttribute("book") Book book, BindingResult errors) {
try {
pay(book);
} catch (InsufficientFundsException ex) {
errors.reject("insufficient.funds");
}
return new ModelAndView(blahblahblah);
}
Вариант 2: пересылка BindingResult на сервисный уровень
Второй способ состоял в том, чтобы передать объект BindingResult на уровень сервиса и вызывать дополнительные ошибки.
Услуги:
public void pay(Book book, BindingResult errors) {
// User has insufficient funds, so...
errors.reject("insufficient.funds);
}
Я вижу проблемы с обоими этими способами. Вариант 1 чувствует себя неловко, потому что не только я должен поймать исключение, я должен добавить ошибку к результату привязки, поэтому мне кажется, что я делаю то же самое дважды. А вариант 2, похоже, слишком сильно привязывает сервисный уровень к контроллеру.
Наконец, я понимаю, что есть SimpleMappingExceptionResolver
, который может использоваться в сочетании с Вариантом 1, но я не уверен, насколько это уместно (возможно, я не видел подходящего примера?). В приведенном выше примере давайте просто скажем для аргумента ради того, что я хотел бы, чтобы пользователь вернулся к исходной форме с красной ошибкой над формой, а не перенаправлен на совершенно другую страницу. SimpleMappingExceptionResolver мне кажется полезным, когда вы хотите перенаправить пользователя на стандартную страницу ошибок, когда возникает определенное исключение (что совсем не то, что я хочу знать, как это сделать).