Skip to content

Тема 36. Spring MVC

Alesey edited this page Dec 11, 2021 · 13 revisions

Материал находится на стадии "Черновик"

Содержание:

  1. Паттерн MVC
  2. Spring-контроллеры
  3. Шаблонизаторы
  4. Обзор и подключение Swagger
  5. Обработка ошибок
  6. Список литературы/курсов

Паттерн MVC

Статическая страница на HTML не умеет реагировать на действия пользователя. Для двухстороннего взаимодействия нужны динамические веб-страницы. MVC — ключ к пониманию разработки динамических веб-приложений, поэтому разработчику нужно знать эту модель.

MVC расшифровывается как модель-представление-контроллер (от англ. model-view-controller). Это способ организации кода, который предполагает выделение блоков, отвечающих за решение разных задач. Один блок отвечает за данные приложения, другой отвечает за внешний вид, а третий контролирует работу приложения. Компоненты MVC:

Модель (model) — этот компонент отвечает за данные, а также определяет структуру приложения. Например, если вы создаете To-Do приложение, код компонента model будет определять список задач и отдельные задачи. самая независимая часть системы. Настолько независимая, что она не должна ничего знать о модулях Вид и Контроллер. Модель настолько независима, что ее разработчики могут практически ничего не знать о Виде и Контроллере.

Представление (view) — этот компонент отвечает за взаимодействие с пользователем. То есть код компонента view определяет внешний вид приложения и способы его использования. Основное предназначение Представления — предоставлять информацию из Модели в удобном для восприятия пользователя формате. Основное ограничение Представления — он никак не должен изменять модель.

Контроллер (controller) — этот компонент отвечает за связь между model и view. Код компонента controller определяет, как сайт реагирует на действия пользователя. По сути, это мозг MVC-приложения. Основное предназначение Контроллера — обрабатывать действия пользователя. Именно через Контроллер пользователь вносит изменения в модель. Точнее в данные, которые хранятся в модели.

Разберем паттерн MVC на примере магазина сэндвичей.

Представьте, что вы пришли в магазин или кафе, где можно заказать сэндвич. В меню есть бутерброды с тунцом, индейкой и ветчиной. Вы заказываете сэндвич с индейкой.

Продавец или бармен с полуслова понимает вас. Он поворачивается в сторону кухни и говорит поварам, чтобы они приготовили сэндвич с индейкой.

У поваров под рукой есть разные продукты: тунец, индейка, ветчина, сыр, листья салата и другие ингредиенты, которые добавляют в бутерброды. Они выбирают только то, что нужно для вашего сэндвича с индейкой. Вы получаете свой заказ.

Покупку бутерброда можно описать через MVC:

Модель: кухня, на которой повар делает сэндвич. Представление: готовый бутерброд, который вы с удовольствием едите. Контроллер: продавец или бармен, который принимает заказ и передаёт его на кухню.

к

Из всего этого можно сделать вполне логичный вывод. Сложную систему нужно разбивать на модули.

Ключевая идея MVC состоит в том, что любое приложение с пользовательским интерфейсом в первом приближении можно разбить на 2 модуля: модуль, отвечающий за реализацию бизнес-логики приложения, и пользовательский интерфейс.

В первом модуле будет реализован основной функционал приложения. Данный модуль будет ядром системы, в котором реализуется модель предметной области приложения. В концепции MVC данный модуль будет нашей буковкой M, т.е. моделью.

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

Основная цель такого разделения — сделать так, чтобы ядро системы (Модель в терминологии MVC) могла независимо разрабатываться и тестироваться.

Архитектура приложения после подобного разделения будет выглядеть следующим образом:

к

Шаг 2. Используя шаблон Наблюдатель, добиться еще большей независимости модели, а также синхронизации пользовательских интерфейсов Здесь мы преследуем 2 цели: Добиться еще большей независимости модели. Синхронизировать пользовательские интерфейсы. Понять, что подразумевается под синхронизацией пользовательских интерфейсов, поможет следующий пример.

Предположим, мы покупаем билет в кино через интернет и видим количество свободных мест в кинотеатре. Одновременно с нами покупать билет в кино может кто-то еще. Если этот кто-то купит билет раньше нас, нам бы хотелось увидеть, что количество свободных мест на наш сеанс уменьшилось.

А теперь поразмышляем о том, как это может быть реализовано внутри программы. Предположим, у нас есть ядро системы (наша модель) и интерфейс (веб страница, на которой мы осуществляем покупку).

На сайте 2 пользователя одновременно выбирают место.

Первый пользователь купил билет. Второму пользователю необходимо отобразить на странице эту информацию.

Как это должно произойти?

Если мы из ядра системы будем обновлять интерфейс, наше ядро, наша модель, будет зависима от интерфейса. При разработке и тестировании модели придется держать в голове различные способы обновления интерфейса.

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

Шаблон Наблюдатель позволяет модели с одной стороны информировать интерфейс (вид и контроллер) о том, что в ней произошли изменения, а с другой — фактически ничего о них “не знать”, и тем самым оставаться независимой. С другой стороны, это позволит синхронизировать пользовательские интерфейсы. Шаг 3. Разделение интерфейса на Вид и Контроллер Продолжаем делить приложение на модули, но уже на более низком уровне иерархии. На этом шаге пользовательский интерфейс (который был выделен в отдельный модуль на шаге 1) делится на вид и контроллер.

Сложно провести строгую черту между видом и контроллером. Если говорить о том, что вид — это то, что видит пользователь, а контроллер — это механизм, благодаря которому пользователь может взаимодействовать с системой, можно обнаружить некоторое противоречие.

Элементы управления, например, кнопки на веб-странице или виртуальная клавиатура на экране телефона, это по сути часть контроллера. Но они так же видны пользователю, как и любая часть вида.

Здесь скорее речь идет о функциональном разделении. Основная задача пользовательского интерфейса — обеспечить взаимодействие пользователя с системой. Это означает, что у интерфейса всего 2 функции: выводить и удобно отображать пользователю информацию о системе; вводить данные и команды пользователя в систему (передавать их системе); Данные функции и определяют то, как нужно делить интерфейс на модули.

В итоге, архитектура системы выглядит так:

к

Итак, у нас появилось приложение из трех модулей, которые называются Модель, Вид и Контроллер.

Резюмируем: Следуя принципам MVC, систему нужно разделять на модули. Самым важным и независимым модулем должна быть модель. Модель — ядро системы. Нужна возможность разрабатывать и тестировать ее независимо от интерфейса. Для этого на первом шаге сегрегации системы нужно разделить ее на модель и интерфейс. Далее, с помощью шаблона Наблюдатель, укрепляем модель в ее независимости и получаем синхронизацию пользовательских интерфейсов. Третьим шагом делим интерфейс на контроллер и вид. Все, что на ввод информации от пользователя в систему — это в контроллер. Все что на вывод информации от системы к пользователю — это в вид.

Немного о взаимосвязи Вида и Контроллера с Моделью Когда пользователь вводит информацию через контроллер, он тем самым вносит изменения в модель. По крайней мере, пользователь вносит изменения в данные модели.

Когда пользователь получает информацию через элементы интерфейса (через Вид), пользователь получает информацию о данных модели.

Как это происходит? Посредством чего Вид и Контроллер взаимодействуют с моделью? Ведь не может быть так, что классы Вида напрямую используют методы классов Модели для чтения/записи данных, иначе ни о какой независимости Модели не может быть и речи.

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

Для связи Модели с Видом и Контроллером необходимо реализовать шаблон проектирования Фасад. Фасад модели будет той самой прослойкой между Моделью и интерфейсом, через которую Вид получает данные в удобном формате, а Контроллер изменяет данные, вызывая нужные методы фасада.

Схематично, в итоге, все будет выглядеть так:

к

MVC: в чем профит? Основная цель следования принципам MVC — отделить реализацию бизнес-логики приложения (модели) от ее визуализации (вида).

Такое разделение повысит возможность повторного использования кода.

Польза применения MVC наиболее наглядна в случаях, когда пользователю нужно предоставлять одни и те же данные в разных формах. Например, в виде таблицы, графика или диаграммы (используя различные виды). При этом, не затрагивая реализацию видов, можно изменить реакции на действия пользователя (нажатие мышью на кнопке, ввод данных).

Если следовать принципам MVC, можно упростить написание программ, повысить читаемость кода, сделать легче расширение и поддержку системы в будущем.

Spring-контроллеры

Шаблонизаторы

Обзор и подключение Swagger

Swagger - это стандартизированная и полная структура для генерации, описания, вызова и визуализации веб-сервисов RESTful.

Общая цель - позволить клиенту и файловой системе обновляться с той же скоростью, что и сервер. Метод, параметры и модель файла тесно интегрированы в код на стороне сервера, что позволяет API всегда оставаться в синхронизации. Swagger никогда не делала управление развертыванием и использование мощных API настолько простым.

Преимущества использования

  • Swagger может создать интерактивную консоль API, которую разработчики могут использовать для быстрого изучения и опробования API.

  • Swagger может генерировать клиентский SDK-код для реализации на различных платформах.

  • Файлы Swagger могут автоматически генерироваться из комментариев кода на многих различных платформах.

  • Swagger имеет сильное сообщество со многими влиятельными участниками.

Swagger — удобный инструмент для создания документации API, который помогает разработчикам сэкономить время. Он предлагает несколько решений для интеграции в проект и формирования интерактивной версии документации, с которой будет удобно взаимодействовать другим разработчикам, внешним пользователям, клиентам.

Swagger — это набор инструментов, которые помогают описывать API. Благодаря ему пользователи и машины лучше понимают возможности REST API без доступа к коду. С помощью Swagger можно быстро создать документацию и отправить ее другим разработчикам или клиентам.

В 2015 году проект Swagger сделали открытым и передали OpenAPI Initiative. Теперь сама спецификация называется OpenAPI. Swagger — инструментарий для работы с OpenAPI, название которого используется в коммерческих и некоммерческих продуктах. Если кто-то называет саму спецификацию Swagger, то это не совсем верно.

Документ спецификации OpenAPI использует YAML, но также может быть написан в формате JSON. Сам по себе он является объектом JSON.

Основные подходы Swagger предлагает два основных подхода к генерированию документации:

Автогенерация на основе кода. Самостоятельная разметка-написание. Первый подход проще. Мы добавляем зависимости в проект, конфигурируем настройки и получаем документацию. Сам код из-за этого может стать менее читабельным, документация тоже не будет идеальной. Но задача минимум решена — код задокументирован.

Чтобы пользоваться вторым подходом, нужно знать синтаксис Swagger. Описания можно готовить в формате YAML/JSON. Можно упростить эту задачу, используя Swagger Editor. Конечно, второй подход позволяет сделать документацию более качественной и кастомной для каждого конкретного проекта и его особенностей, к тому же все не так сложно как может показаться, это потребует минимальных дополнительных усилий.

Swagger Core Это Java-реализация спецификации. Для ее использования потребуется:

Java 8 и выше Apache Maven 3.0.4 и выше Jackson 2.4.5 и выше Для его внедрения в проект используются две зависимости. Вот примеры:

io.swagger.core.v3 swagger-annotations 2.1.11 org.springdoc springdoc-openapi-ui 1.5.2 Другой способ — настроить maven-плагин. Тогда описания при сборке проекта будут генерироваться в файл YAML. Пример: org.springdoc springdoc-openapi-maven-plugin 0.3 integration-test generate http://localhost:3080/v3/api-docs openapi.yaml ${project.build.directory} Для конфигурации нужны еще два бина (beans). В них мы описываем название приложения, версию API, добавляем другие важные данные. Посмотреть примеры можно в этом репозитории на GitHub. В нем представлены образцы Swagger Core из библиотеки Java. Каждый образец содержит файл Readme, в котором подробно описано, как его запускать и что проверять.

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

Аннотация Использование @Operation Для описания операции или метода HTTP @Parameter Для представления одного параметра в операции @RequestBody Для представления тела запроса в операции @ApiResponse Для представления тела ответа в операции @Tag Для представления тегов операции или определения OpenAPI @Server Для представления серверов операции или определения OpenAPI @Callback Для описания набора запросов @Link Для представления ссылки времени разработки для ответа @Schema Для определения входных и выходных данных @ArraySchema Для определения входных и выходных данных для типов массивов @Content Для представления схемы и примеров для мультимедиа @Hidden Для скрытия ресурса, операции или свойстваSwagger Codegen Это проект для автоматического генерирования клиентских библиотек API, заглушек сервера и документации. Поддерживает большое количество технологий. Посмотреть полный список можно в репозитории Swagger Codegen на GitHub.

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

API клиенты ActionScript, Ada, Apex, Bash, C#, C++, Clojure, Dart, Elixir, Elm, Eiffel, Erlang, Go, Groovy, Haskell, Java (Jersey1.x, Jersey2.x, OkHttp, Retrofit1.x, Retrofit2.x, Feign, RestTemplate, RESTEasy, Vertx, Google API Client Library for Java, Rest-assured), Kotlin, Lua, Node.js, Objective-C, Perl, PHP, PowerShell, Python, R, Ruby, Rust (rust, rust-server), Scala (akka, http4s, swagger-async-httpclient), Swift (2.x, 3.x, 4.x, 5.x), Typescript Заглушки Ada, C# (ASP.NET Core, NancyFx), C++ (Pistache, Restbed), Erlang, Go, Haskell (Servant), Java (MSF4J, Spring, Undertow, JAX-RS: CDI, CXF, Inflector, RestEasy, Play Framework, PKMST), Kotlin, PHP (Lumen, Slim, Silex, Symfony, Zend Expressive), Python (Flask), NodeJS, Ruby (Sinatra, Rails5), Rust (rust-server), Scala (Finch, Lagom, Scalatra) Генераторы документации HTML, Confluence Wiki Файлы конфигурации Apache2 Другое JMeter для нагрузочного тестирования Плюсы Swagger Codegen:

Генерирование серверов — позволяет избавиться от рутины, создавая шаблонный код на 20+ языках. Упрощенное генерирование SDK — можно создавать клиентские наборы на 40+ языках для быстрой интеграции с вашим API. Постоянное обновление инструментов. Чтобы добавить Swagger Codegen в проект, используйте зависимость:

io.swagger.codegen.v3 swagger-codegen-maven-plugin 3.0.24 Как и в случае с Swagger Core, можно настроить maven-плагин для генерации клиента или мок-сервера. org.openapitools openapi-generator-maven-plugin 3.3.4 compile generate spring ${project.basedir}/src/main/resources/api.yaml ${project.build.directory}/generated-sources com.api com.model ApiUtil.java ${project.groupId} ${project.artifactId} ${project.version} true swagger spring-mvc true true java8 true ${project.basedir}/.openapi-generator-ignore Swagger Codegen предоставляет следующие команды:

Config-help — помощь с настройкой выбранного языка. Generate — генерирование кода с выбранным генератором. Help — вывод справочной информации про openapi-generator. List — список доступных генераторов. Meta — генератор набора шаблонов и настроек Codegen. Использует информацию о выбранном языке. Validate — проверка спецификации. Version — отображение используемой версии. Самые полезные команды — generate и validate. Первая позволяет создать клиент, а вторая — проверить его соответствие спецификации. Посмотреть полный список возможностей можно с помощью команды help после запуска jar-файла.

Swagger UI Swagger UI визуализирует ресурсы OpenAPI и взаимодействие с ними без отображения логики реализации. Этот инструмент берет спецификацию и превращает ее в интерактивный проект, где можно выполнять разные запросы для тестирования API.

Плюсы Swagger UI:

Нет зависимостей. Интерфейс доступен в любой среде разработки. Полная поддержка браузерами. Удобное взаимодействие для других разработчиков и клиентов. Можно проверить все операции, предоставляемые API, даже не имея специальных знаний. Простая навигация. Ресурсы и конечные точки представлены в виде аккуратно распределенного на категории списка. Можно настраивать стиль и пользовательский интерфейс так, как вам хочется. Пользовательский интерфейс Swagger полностью размещен в SwaggerHub. Вы можете написать и визуализировать API или импортировать существующие определения для создания интерактивного интерфейса, размещенного в облаке. Благодаря встроенной интерактивности SwaggerHub позволяет безопасно предоставлять доступ к документации внешним пользователям или другим разработчикам.

Swagger Editor Это онлайн-редактор для изменения и проверки API внутри браузера. Позволяет просматривать документацию в реалтайме. С его помощью можно создать описания, а затем использовать их с полным набором инструментов для генерации документации.

Плюсы Swagger Editor:

Работает в любой среде разработки, локально и в сети. Дает обратную связь — показывает ошибки в синтаксисе по мере написания, проверяя его на соответствие OpenAPI. Позволяет мгновенно визуализировать API через Swagger UI. Помогает писать документацию быстрее благодаря интеллектуальному автозаполнению. Предоставляет гибкие инструменты для настройки конфигурации — от темы оформления до межстрочного интервала. Предлагает создание серверных заглушек и клиентских библиотек для вашего API на всех популярных языках.

Обработка ошибок

Список литературы/курсов

Clone this wiki locally