Проверка предварительных условий на уровне контроллера или сервиса

Я использую класс предварительных условий Google для проверки входных данных пользователя.
Но меня беспокоит, где лучше всего проверять входные данные пользователя, используя класс предварительных условий.
Во-первых, я написал проверочный код проверки в контроллере, как показано ниже:

@Controller
...
public void register(ProductInfo data) {
    Preconditions.checkArgument(StringUtils.hasText(data.getName()),
        "Empty name parameter.");
    productService.register(data);
}

@Service
...
public void register(ProductInfo data) {
    productDao.register(data);
}

но я думал, что register метод в слое обслуживания будет использовать другой метод контроллера, как показано ниже:

@Controller
...
public void register(ProductInfo data) {
    productService.register(data);
}
public void anotherRegister(ProductInfo data) {
    productService.register(data);
}

@Service 
...
public void register(ProductInfo data) {
    Preconditions.checkArgument(StringUtils.hasText(data.getName()),
        "Empty name parameter.");
    productDao.register(data);
}

С другой стороны, метод уровня обслуживания будет использоваться только в один контроллер.
Я был сбит с толку. Какой лучший способ проверки предварительных условий в контроллере или службе?
Спасибо заранее.

4 ответов


В идеале вы бы сделали это в обоих местах. Но вы путаете две разные вещи:

  • проверка (с обработкой ошибок)
  • Defensivie Программирование (ака утверждения, ака дизайн по контракту).

вы абсолютно должны сделать проверка в контроллере и защитное Программирование к вашим услугам. И вот почему.

вам нужно проверка для форм и запросов REST, чтобы вы можете отправить разумную ошибку обратно клиенту. Это включает в себя, какие поля плохие, а затем локализацию сообщений об ошибках... так далее... (ваш текущий пример отправит мне ужасное сообщение об ошибке 500 с трассировкой стека, если ProductInfo.name свойство было null).

Весна решение для проверки объектов в контроллере.

защитное Программирование выполняется на уровне сервиса, но не проверка потому что у вас нет доступа к locale для создания правильных сообщений об ошибках. Некоторые так и делают, но весна здесь не помогает.

другая причина, по которой проверка не выполняется на уровне сервиса, заключается в том, что ORM уже обычно делает это через спецификацию проверки JSR Bean (hibernate), но она не генерирует разумные сообщения об ошибках.

одна стратегия, которую люди делают, это создать там собственную библиотеку utils предварительных условий, которая бросает пользовательские производные RuntimeExceptions вместо гуавы (и commons lang)IllegalArgumentException и IllegalStateException а то try...catch исключения в контроллере, преобразующие их в сообщения об ошибках проверки.


нет "лучшего" пути. Если вы думаете, что служба будет использоваться несколькими контроллерами (или другими частями кода), то вполне может иметь смысл делать проверки там. Если для вашего приложения важно проверять недопустимые запросы, пока они все еще находятся в контроллере, вполне может иметь смысл делать проверки там. Эти двое, как вы заметили, не исключают друг друга. Возможно, вам придется проверить дважды, чтобы охватить оба сценария.

другое возможное решение: используйте Bean Validation (JSR-303), чтобы поместить проверки (предварительные условия) на сам компонент ProductInfo. Таким образом, вы указываете проверки только один раз, и все, что нужно, может быстро проверить компонент.


Я думаю, что в вашем частном случае вам нужно проверить его на уровне обслуживания и вернуть исключение контроллеру в случае ошибки целостности данных.

@controller
public class MyController{

@ExceptionHandler(MyDataIntegrityExcpetion.class)
public String handleException(MyDataIntegrityExcpetion ex, HttpServletRequest request) {
  //do someting on exception or return some view. 
}

}

Это также зависит от того, что вы делаете в контроллер. возвращаете ли вы View или просто используете @ResponseBody Примечание. Spring MVC имеет хорошее решение "из коробки" для проверки ввода/dat я рекомендую вам проверить эти библиотеки.

http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/validation.html


предварительные условия, проверки, будь то простые или деловые, должны обрабатываться на уровне фильтра или перехватчиками даже до достижения уровня контроллера или сервиса.

опасность, если вы установите ее в своем уровне контроллера, вы нарушаете принцип единой ответственности контроллера, единственной целью которого является делегирование запроса и ответа.

ввод предварительных условий в слой обслуживания вводит сквозные проблемы к ядру бизнес.

фильтр или inceptor построен для этой цели. Размещение предварительных условий на уровне фильтра или в перехватчиках также позволяет вам "выбирать и сопоставлять" правила, которые вы можете поместить в стек для каждого запроса сервлета, таким образом, не ограничивая конкретное правило только одним запросом сервлета или не вводя дублирование.