1. Обзор
В этом руководстве мы обсудим проверку Spring на сервисном уровне приложения Java. Хотя Spring Boot поддерживает бесшовную интеграцию с пользовательскими валидаторами, стандартом де-факто для выполнения валидации является Hibernate Validator .
Здесь мы узнаем, как перенести нашу логику проверки из наших контроллеров в отдельный сервисный уровень. Кроме того, мы реализуем проверку на уровне службы в приложении Spring.
2. Слои приложений
В зависимости от требований бизнес-приложения Java могут принимать различные формы и типы. Например, мы должны определить, какие слои требуются нашему приложению на основе этих критериев. Если нет особой необходимости, многие приложения не выиграют от дополнительной сложности и затрат на обслуживание уровней обслуживания или репозитория.
Мы можем решить все эти проблемы, используя несколько слоев. Эти слои:
Уровень потребителя или веб-уровень — это самый верхний уровень веб-приложения. Он отвечает за интерпретацию вводимых пользователем данных и предоставление соответствующего ответа . Исключения, создаваемые другими уровнями, также должны обрабатываться веб-уровнем. Поскольку веб-уровень является точкой входа нашего приложения, он отвечает за аутентификацию и служит первой линией защиты от неавторизованных пользователей.
Под веб-слоем находится сервисный уровень. Он служит транзакционным барьером и содержит как приложения, так и службы инфраструктуры. Кроме того, общедоступный API сервисного уровня предоставляется прикладными сервисами. Они часто служат границей транзакций и отвечают за авторизацию транзакций . Инфраструктурные службы предоставляют «программный код», который подключается к внешним инструментам, включая файловые системы, базы данных и серверы электронной почты. Эти подходы часто используются несколькими службами приложений.
Нижний уровень веб-приложения — это уровень сохраняемости. Другими словами, он отвечает за взаимодействие с хранилищем данных пользователя.
3. Проверка на сервисном уровне
Сервисный уровень — это уровень в приложении, который облегчает связь между контроллером и уровнем постоянства. Кроме того, бизнес-логика хранится на сервисном уровне. В частности, он включает логику проверки. Состояние модели используется для связи между уровнями контроллера и сервиса.
У обращения с валидацией как с бизнес-логикой есть свои преимущества и недостатки, и архитектура проверки (и привязки данных) Spring не препятствует этому. Проверка, в частности, не должна быть привязана к веб-уровню, должна быть простой для локализации и должна позволять использовать любой доступный валидатор.
Кроме того, входные данные клиента не всегда проходят через процесс контроллера REST, и если мы не проверим их также на уровне службы, могут пройти неприемлемые данные, что вызовет несколько проблем . В этом случае мы будем использовать стандартную схему проверки Java JSR-303 .
4. Пример
Давайте рассмотрим простую форму регистрации учетной записи пользователя, разработанную с использованием Spring Boot.
4.1. Простой доменный класс
Для начала у нас будут только атрибуты имени, возраста, телефона и пароля:
public class UserAccount {
@NotNull(message = "Password must be between 4 to 15 characters")
@Size(min = 4, max = 15)
private String password;
@NotBlank(message = "Name must not be blank")
private String name;
@Min(value = 18, message = "Age should not be less than 18")
private int age;
@NotBlank(message = "Phone must not be blank")
private String phone;
// standard constructors / setters / getters / toString
}
Здесь, в приведенном выше классе, мы использовали четыре аннотации — @NotNull
, @Size
, @NotBlank
и @Min
— чтобы убедиться, что входные атрибуты не являются ни нулевыми, ни пустыми и соответствуют требованиям к размеру.
4.2. Внедрение проверки на сервисном уровне
Существует множество доступных решений для проверки, при этом Spring или Hibernate обрабатывают фактическую проверку. С другой стороны, ручная проверка является жизнеспособной альтернативой . Когда дело доходит до интеграции проверки в правильную часть нашего приложения, это дает нам большую гибкость.
Далее давайте реализуем нашу проверку в классе обслуживания:
@Service
public class UserAccountService {
@Autowired
private Validator validator;
@Autowired
private UserAccountDao dao;
public String addUserAccount(UserAccount useraccount) {
Set<ConstraintViolation<UserAccount>> violations = validator.validate(useraccount);
if (!violations.isEmpty()) {
StringBuilder sb = new StringBuilder();
for (ConstraintViolation<UserAccount> constraintViolation : violations) {
sb.append(constraintViolation.getMessage());
}
throw new ConstraintViolationException("Error occurred: " + sb.toString(), violations);
}
dao.addUserAccount(useraccount);
return "Account for " + useraccount.getName() + " Added!";
}
}
Валидатор
является частью Bean Validation API и отвечает за проверку объектов Java . Кроме того, Spring автоматически предоставляет экземпляр Validator
, который мы можем внедрить в нашу службу UserAccountService
. Validator используется для проверки переданного объекта в функции validate
(..)
. Результатом является набор
ConstraintViolation
.
Если никакие ограничения проверки не нарушены (объект действителен), набор
пуст. В противном случае мы выбрасываем ConstraintViolationException
.
4.3. Реализация REST-контроллера
После этого давайте создадим класс Spring REST Controller для отображения службы клиенту или конечному пользователю и оценки проверки ввода для приложения:
@RestController
public class UserAccountController {
@Autowired
private UserAccountService service;
@PostMapping("/addUserAccount")
public Object addUserAccount(@RequestBody UserAccount userAccount) {
return service.addUserAccount(userAccount);
}
}
Мы не использовали аннотацию @Valid
в приведенной выше форме контроллера REST, чтобы предотвратить любую проверку.
4.4. Тестирование REST-контроллера
Теперь давайте проверим этот метод, запустив приложение Spring Boot. После этого, используя Postman или любой другой инструмент тестирования API, мы опубликуем ввод JSON по URL-адресу localhost:8080/addUserAccount
:
{
"name":"ForEach",
"age":25,
"phone":"1234567890",
"password":"test",
"useraddress":{
"countryCode":"UK"
}
}
Убедившись, что тест проходит успешно, давайте теперь проверим, работает ли проверка в соответствии с ожиданиями. Следующий логический шаг — протестировать приложение с несколькими недопустимыми входными данными. Следовательно, мы обновим наш входной JSON недопустимыми значениями:
{
"name":"",
"age":25,
"phone":"1234567890",
"password":"",
"useraddress":{
"countryCode":"UK"
}
}
Консоль теперь показывает сообщение об ошибке. Следовательно, мы можем видеть, насколько важно использование Validator для проверки :
Error occurred: Password must be between 4 to 15 characters, Name must not be blank
5. Плюсы и минусы
На уровне обслуживания/бизнеса это часто является успешным подходом к проверке. Он не ограничивается параметрами метода и может применяться к различным объектам. Мы можем, например, загрузить объект из базы данных, изменить его, а затем проверить его перед продолжением.
Мы также можем использовать этот метод для модульных тестов, чтобы мы могли фактически смоделировать класс Service. Чтобы облегчить реальную проверку в модульных тестах, мы можем вручную сгенерировать необходимый экземпляр Validator
.
Ни в том, ни в другом случае в наших тестах не требуется загрузка контекста приложения Spring.
6. Заключение
В этом кратком руководстве мы рассмотрели различные уровни бизнес-приложений Java. Мы узнали, как перенести нашу логику проверки из наших контроллеров в отдельный сервисный уровень. Кроме того, мы реализовали один подход к выполнению проверки на сервисном уровне приложения Spring.
Код в примерах доступен на GitHub .