Skip to content

Latest commit

 

History

History
895 lines (534 loc) · 79.2 KB

File metadata and controls

895 lines (534 loc) · 79.2 KB

Вопросы для собеседования

Spring

Spring Core

Что такое Spring Framework?

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

Востребованность Spring:

  • Один из самых популярных web-фреймворков в мире.
  • Самый популярный Java-фреймворк.
  • Java - один из самых популярных ЯП в мире. Spring обычно используется везде, где используется Java.
  • Очень востребован работодателями по всему миру.

Spring Framework состоит из множества компонентов => облегчает множество аспектов разработки приложений на Java. Компоненты:

  • Контекст приложения (Application Context) и Внедрение зависимостей (Dependency Injection).
  • Удобный и эффективный доступ к БД (замена JDBC).
  • Компонент для разработки web-приложений на Java (Spring MVC).
  • Множество других полезных компонентов (spring.io).

В чем преимущества Spring?

  • Spring является легким в использовании ресурсов, при этом базовая структура Spring весит всего 2 МБ памяти.
  • Масштабируемость: интерфейс управления транзакциями Spring может масштабироваться как до локальной транзакции в одной базе данных, так и до глобальных транзакций с помощью модуля JTA
  • Обработка исключений: Обработка исключений проста благодаря многочисленным ресурсам API для обработки исключений в каждом модуле.
  • Многоуровневая архитектура: Позволяет использовать нужные части программы и отказаться от остальных.
  • Включено POJO: Простое старое объектное программирование на Java обеспечивает непрерывную тестируемость и интеграцию.
  • С открытым исходным кодом: Бесплатно для всех и без блокировки поставщика.
  • Инверсия управления (IOC): Достигается свободная связь через IOC, позволяя объектам передавать свои зависимости другим объектам, а не зависимым объектам.
  • Аспектно-ориентированный (AOP): Spring поддерживает аспектно-ориентированное программирование, парадигму, которая отделяет бизнес-логику приложений от системных служб.

Каковы различные компоненты приложения Spring?

Приложения Spring содержат пять компонентов:

  • Интерфейс: Определяет функции программы.
  • Класс компонента: Содержит свойства, методы настройки и получения для доступа к компоненту, а также определенные функции и т.д.
  • Spring Аспектно-ориентированное программирование (AOP): Включает в себя сквозные функциональные возможности, которые не поддерживаются в объектно-ориентированном программировании.
  • Файл конфигурации компонента: Содержит информацию о классах, способах их настройки и определяет их взаимосвязи.
  • Пользовательская программа: Вызывает функции по всей программе

Application Context & Dependency Injection

Типичное Java приложение - это набор Java объектов, которые взаимодействуют друг с другом и ссылаются друг на друга.

image

Кргда Java приложение запускается, все необходимые Java объекты создаются и помещаются в оперативную память. В ходе работы приложения, объекты могут добавляться / удаляться. Также могут изменяться связи между объектами. Большое количество объектов и связей между ними встречается в любом более-менее сложном Java приложении. Spring помогает нам в работе с множеством объектов.

Существуют некоторые проблемы при создании приложений, например, нужно что бы конкретный объект создавался только один раз (пример Database). Можно решить это без Spring с помощью паттерна Singleton. но для этого требуется дополнительный код. Еще одна проблема, что нужно внедрять ссылку на этот единственный объект (Database) во все остальные классы, выстроить иерархию. Можно сделать вручную, но это очень сложно и запутанно.

image

image

Spring Framework дает возможность удобного и эффективного доступа к БД, предоставляет для этого множество инструментов для взаимодействия с БД. JDBC - примитивный и неудобный способ взаимодествия с БД. Он не подходит для сложных приложений, слишком низкоуровневый.

Spring MVC - компонент Spring Framework, который позволяет создавать Web - приложения. Огромное количество Web - приложений в интернете работают на Spring MVC. Помимо этого, Spring MVC часто используется в качестве backend - API для мобильных приложений.

Что такое файл конфигурации для Spring?

Файл конфигурации для Spring представляет собой XML-файл, содержащий информацию о классе для проекта. Они описывают конфигурацию каждого класса, то, как они представлены другим классам, и зависимости во всей программе.

Наполнение конфигурационного файла Spring

Конфигурационный файл Spring должен называться applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans  xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="testBean"
        class="ru.kirillova.springcourse.TestBean">
        <constructor-arg value="Neil"/>
    </bean>
</beans>

Это стандартная конфигурация, которая позволяет использовать Spring Framework. В теге <bean> создается новый бин, у него есть id - уникальный идентификатор объекта, class- путь к классу, бин которого мы хотим создать, TestBean - название класса, бин которого мы хотим создать, "ru.kirillova.springcourse.TestBean" - соответственно сам путь до класса, <constructor-arg> - передаем параметры для конструктора для создания бина.

Inversion of Control (IoC)

Инверсия управления

image

image

image

Что такое Spring IoC контейнер?

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

Каковы типы IoC?

  • Контейнер BeanFactory: Этот заводской класс содержит предварительно упакованную коллекцию компонентов, которые создаются при вызове клиентами. Это самый простой контейнер для поддержки DI.
  • Контейнер ApplicationContext: Построенный поверх контейнера BeanFactory, этот контейнер обеспечивает дополнительные функциональные возможности, ориентированные на предприятие. Например, контейнеры ApplicationContext предоставляют возможность разрешать текстовые сообщения и публиковать события приложения.

Что такое Аспектно-ориентированное программирование (AOП)?

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

Что такое Bean?

Это объекты, созданные из метаданных конфигурации при их передаче в контейнер IOC. Они составляют основу всех Spring. Контейнер IOC создает экземпляры, настраивает, подключает и управляет каждым компонентом. Это просто Java объект. Когда Java объекты создаются с помощью Spring'а они называются бинами (beans). Бины создаются из Java классов (так же, как и обычные объекты).

<bean id="testBean"
        class="ru.kirillova.springcourse.TestBean">
        <constructor-arg value="Neil"/>
</bean>

image

MusicPlayer слабо зависит от интерфейса Music. В методе playMusic() видим, что MusicPlayer сам создает свои зависимости, даже если будем использовать Spring Framework, мы будем сами обращаться к application context'у и будем сами извлекать из него созданный бин.

image

Inversion of Control - это такой архитектурный подход, когда сущность не сама создает свои зависимости, а когда зависимости для этой сущности поставляются извне.

image

image

image

Решние этой проблемы с помощью внедрения зависимостей (Dependency Injection) с помощью Spring Framework будет рассмотрена далее.

Смотри код в папке spring-app1 или уроки №5,6, показано на практике внедрение зависимостей и создание бинов на примере MusicPlayer

Какие есть способы конфигурации Spring Framework?

  • XML файл когфигурации (старый способ, но многие существующие приложения до сих пор его используют, будут рассмотрены несколько примеров далее с его использованием).
  • Java аннотации и немного XML (современный способ).
  • Вся конфигурация на Java коде (современный способ).

Как создать ApplicationContext в программе Java?

В независимой Java программе ApplicationContext можно создать следующим образом:

  • AnnotationConfigApplicationContext: при использовании Spring в качестве автономного приложения можно создать, инициализировать контейнер с помощью аннотаций.
  • ClassPathXmlApplicationContext: второй подход использует xml файл, в котором задаются необходимые настройки, а затем используем класс для загрузки файла и получения объекта контейнера.
  • FileSystemXmlApplicationContext: аналогичен варианту с xml, но с возможностью загрузки файла конфигурации из любого места файловой системы.

Каковы общие реализации ApplicationContext?

Тремя наиболее популярными контейнерами являются:

  • AnnotationConfigApplicationContext: Эта реализация позволяет создавать ApplicationContext на основе аннотаций конфигурации. Вы можете указать классы конфигурации, содержащие аннотации, такие как @Configuration и @Bean, и ApplicationContext создаст бины на основе этих аннотаций.
  • FileSystemXmlApplicationContext: Заставляет конструктор загружать определения компонентов из файла конфигурации XML. На него должен быть указан полный путь к файлу.
  • ClassPathXmlApplicationContext: Этот контейнер выполняет то же самое, что и выше, но не требует полного пути к файлу. Вместо этого вы устанавливаете свойство CLASSPATH и позволяете контейнеру находить XML по этому CLASSPATH.
  • WebXmlApplicationContext: Загружает все определения компонентов в веб-приложение из XML-файла.
  • AnnotationConfigWebApplicationContext: Эта реализация предназначена для веб-приложений и позволяет создавать ApplicationContext на основе аннотаций конфигурации. Она автоматически обнаруживает классы конфигурации, используемые в вашем веб-приложении, и создает бины на основе этих аннотаций.

В чем разница между BeanFactory и ApplicationContext?

BeanFactory – это базовый, компактный контейнер с ограниченной функциональностью. Его лучше всего использовать для простых задач или при использовании машин с низким ресурсом. ApplicationContext – это расширенный, более интенсивный контейнер с расширенным интерфейсом и дополнительными возможностями, такими как AOP. Этот контейнер лучше всего использовать, когда вам требуется больше функциональности, чем на заводе Bean, и у вас достаточно ресурсов, доступных на машине.

Типичные шаги в работе со Spring

  • Создаем Java классы (будущие бины)
  • Создаем и связываем бины с помощью Spring (аннотации, XML или Java код)
  • При использовании, все объекты (бины) берутся из контейнера Spring

Dependency Ijection

Внедрение зависимостей (DI) - это концепция, которая определяет, как должно быть связано несколько классов. Это один из примеров Инверсии контроля. Вам не нужно явно подключать службы и компоненты в коде при использовании внедрения зависимостей. Вместо этого вы описываете службы, необходимые каждому компоненту, в файле конфигурации XML и разрешаете контейнеру IOC автоматически подключать их. К достоинствам применения DI можно отнести:

  • Сокращение объема связующего кода, который должен быть написан для связывания вместе различных компонентов приложения. Зачастую этот код очень прост — при создании зависимости должен создаваться новый экземпляр соответствующего объекта.
  • Упрощенная конфигурация приложения. Для конфигурирования классов, которые могут быть внедрены в другие классы, можно использовать аннотации или XML-файлы.
  • Возможность управления общими зависимостями в единственном репозитории (в Spring есть возможность хранить эту информацию в XML-файлах или Java классах), что существенно упрощает управление зависимостями и снижает количество возможных ошибок.
  • Улучшенная возможность тестирования. Когда классы проектируются для DI, становится возможной простая замена зависимостей. Это особенно полезно при тестировании приложения.
  • Стимулирование качественных проектных решений для приложений. Вообще говоря, проектирование для DI означает проектирование с использованием интерфейсов. Используя Spring, вы получаете в свое распоряжение целый ряд средств DI и можете сосредоточиться на построении логики приложения, а не на поддерживающей DI платформе.

Способы внедрения зависимостей

  • Через конструктор
  • Через setter
  • Можно внедрять ссылки или простые значения
  • Можно внедрять значения из внешнего файла
  • Есть множество конфигураций того, как внедрять (scope, init-method, destroy-method, factory method и т.д.)
  • Можно внедрять через XML, Java-аннотации или Java код
  • Процесс внедрения можно автоматизировать (Autowiring)

image

image

image

Что такое scope?

Scope задает то, как Spring будет создавать ваши бины. Есть такой scope, который называется Singleton, он используется по умолчанию. Singleton - это паттерн программирования.

Если не указывать scope, то по умолчанию Singleton:

<bean id="musicBean"
	class="ru.kirillova.springcourse.ClassicalMusic">
</bean>
  • По умолчанию создается один объект (он создается до вызова метода getBean()).
  • При всех вызовах getBean() возвращается ссылка на один и тот же единственный объект.

Scope Singleton чаще всего используется тогда, когда у нашего бина нет изменяемых состояний (stateless). Потому что если будем изменять состояние у Singleton бина, столкнемся с проблемой.

image

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

Еще один scope, который называется Prototype, каждый раз создает новый объект при вызове getBean(). Используется, когда у бина есть изменяемые состояния (stateful).

Другие scope'ы , такие как request, session, flobal-session, будут изучены в разделе Spring MVC.

Жизненный цикл бина (Bean Lifecycle)

смотри код в папке C:\IntelliJ IDEA workspace\SpringCourse\Lesson8.InitDestroyAndFactory

Каковы этапы жизненного цикла компонента?

Жизненный цикл компонента состоит из семи этапов:

  • Создать экземпляр: Компонент создается контейнером Spring с использованием определения компонента, найденного в файле конфигурации XML.
  • Заполнение свойств: Spring заполняет все определенные свойства из XML-файла с помощью внедрения зависимостей.
  • Установить имя компонента: Spring передает идентификатор компонента методу setBeanName(), если компонент использует интерфейс BeanNameAware.
  • Установить baen factory: Spring передает beanfactory методу setBeanFactory(), если компонент настроен на использование интерфейса BeanFactoryAware.
  • Предварительная инициализация: Spring вызывает любые BeanPostProcessors, связанные с компонентом, с помощью метода postProcessorBeforeInitialization().
  • Инициализация: Затем инициализируется компонент. Выполняется любой специальный процесс инициализации, указанный в методе инициализации.
  • Постинициализация: Вызываются все определенные методы postProcessAfterInitialization(). Теперь bean завершен. Компоненты, реализующие DisposableBean, будут удалены с помощью функции destroy() после завершения их работы.

Является ли Spring бин потокобезопасным?

По умолчанию бин задается как синглтон в Spring. Таким образом все публичные переменные класса могут быть изменены одновременно из разных мест. Так что — нет, не является. Однако поменяв область действия бина на request, prototype, session он станет потокобезопасным, но это скажется на производительности.

Объясните внутреннюю часть bean в Spring

Внутренний компонент используется как свойство другого компонента. Внутренние компоненты могут быть определены в XML-файле конфигурации либо в элементах <property>, либо <constructor-arg>. Все внутренние компоненты всегда имеют область действия как prototype и не имеют идентификаторов.

Что такое автоматическая проводка bean?

Это функция Spring, которая позволяет контейнеру Spring автоматически устанавливать отношения зависимостей между сотрудничающими компонентами, просматривая BeanFactory. Автоматическая проводка может быть настроена для определения этих отношений с использованием имен компонентов, типов или даже конструкторов классов.

Специальные методы бинов

init-method, destroy-method, factory method

image

init-method

Это метод, который запускается в ходе инициализации бина. Используется для инициализации ресурсов, обращения к внешним файлам, запуска БД.

destroy-method

Этот метод, который запускается в ходе уничтожения бина (при завершении приложения). В этом методе обычно происходит очищение ресурсов, закрытие потоков ввода-выводы, закрытие доступа к БД.

image

public class ClassicalMusic implements Music {
    private ClassicalMusic() {}

    public static ClassicalMusic getClassicalMusic() {
        return new ClassicalMusic();
    }

    public void doMyInit() {
        System.out.println("Doing my initialization");
    }

    public void doMyDestroy() {
        System.out.println("Doing my destruction");
    }

    @Override
    public String getSong() {
        return "Hungarian Rhapsody";
    }
}

Тонкости init и destroy методов:

  • Модификатор доступа - может быть любой у обоих методов (public, protected, private).
  • Тип возвращаемого значения - может быть любой, но чаще всего используется void, т.к. нет возможности получить возвращаемое значение.
  • Название метода - может быть любое.
  • Аргументы метода - эти методы не должны принимать на вход какие-либо аргументы.

Для бинов со scope "prototype" Spring не вызывает destroy мотод. Spring не берет на себя полный жизненный цикл бинов со scope "prototype". Spring отдает prototype бины клиенту и больше о них не заботится (в отличие от singleton бинов).

factory method

Фабричный метод (англ. Factory Method) - это паттерн программирования. Если объекты класса создаются фабричным методом, то можно определить factory method.

image

Как все работает

  • У нас есть XML файл, там мы прописываем бины
  • Поднимаем контекст
  • Приходит XmlBeanDefinitionReader, считывает с этого xml все декларации бинов и кладет их в map BeanDefinitions : id бина - декларация бина. В декларацию входит : из какого класса нужно создавать бин, есть ли init-method, если есть, то как он называется, какие properties у этого бина, и все остальные подробности бина, которые мы прописываем в xml.
  • После того как все map BeanDefinitions созданы, BeanFactory начинат по ним работать, создает из наших классов объекты, и все бины складывает в контейнер IoC Container. Если бин Singleton, то умолчанию он создается как только мы поднимаем контекст и сразу складывается в контейнер, а все Prototype создаются только тогда, когда они нужны, т.е. из какого-то участка кода его запросили, Spring его создал, настроил, отдал и забыл про него. Это важно , т.к. если мы прописываем destroy-method для бина, то для Singleton он будет работать, потому что в тот момент когда контекст закрывается Spring проходит по всем бинам, которые хранятся в контейнере, а это только Singleton, находит их destroy-method'ы и запускает их; а Prototype бины Spring нигде не хранит, соответственно для Prototype бинов destroy-method никогда не работает.
  • Из этого контейнера выходят полностью настроенные бины.

Интерфейс BeanPostProcessor

  • Позволяет настраивать наши бины до того, как они попадают в контейнер.
  • У этого интерфейса 2 метода :
    • Object postProcessBeforeInitialization(Object bean, String beanName) - вызывается до init-method'а
    • Object postProcessAfterInitialization(Object bean, String beanName)- вызывается после init-method'а
  • А между ними вызывается init-method:
    • init-method - для xml файла
    • afterPropertieSet - если работаем на Spring2, который не знает про аннотации - устаревший метод, сейчас так не делают.
    • @PostConstruct - для работы с аннотациями

ApplicationListener

Умеет слушать контекст Spring'а, все ивенты, которые с ним происходят:

  • ContextStartedEvent - означает, что контекст начал свое построение.
  • ContextStoppedEvent
  • ContextRefreshedEvent
  • ContextClosedEvent Из любого ивента можно вытащить контекст.

Что такое Java аннотация?

Java аннотация - это специальный тип комментариев в вашем коде с помощью которых можно:

  • Передавать какие-либо инструкции для Java компилятора (пример: @Override).
  • Передавать какие-либо инструкции для анализаторов исходного кода.
  • Передавать метаданные, которые могут быть использованы либо вашим Java приложением(с помощью рефлексии), либо другими приложениями или фреймворками (привет: Spring Framework).

image

Аннотация @Component

  • Помечаем ей класс, если хотим, чтобы Spring создал бин из этого класса.
  • Именно эту аннотацию Spring ищет, когда сканирует все ваши классы.
  • Можно указать id для создаваемого бина, можно не указывать (тогда будет название название_класса_с_маленькой_буквы).

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

<context:component-scan base-package="ru.kirillova.springcourse" />

Теперь при запуске приложения Spring отсканирует все классы в пакете springcourse и создаст бины классов, помеченных аннотацией @Component. Сканирует все классы ClassPathDefinitionScanner и ищет все бины, которые аннотированы @Component. Этот сканер не является ни BeanPostProcessor'ом, ни BeanFactoryPostProcessor'ом. Он является ResourceLoaderAware - подгружает дополнительные ресрсы.

Кто обрабатывает JavaConfig?

  • ConfigurationClassPostProcessor (особый BeanFactoryPostProcessor)
  • Его регистрирует AnnotationConfigApplicationContext
  • Он создает бин-дифинишны по @Bean
  • А так же относится к:
    • @Import
    • @ImportResource
    • @ComponentScan

Аннотация @Autowired

Эта аннотация осущществляет внедрение зависимостей.

image

image

Мы можем внедрять бины указывая конкретный класс, или какой-то интерфейс:

image

image

image

Аннотация @Qualifier

Решает проблему неоднозначности, когда для внедрения подходят несколько бинов.

image

Эту аннотацию можно использовать на :

  • Конструкторах
  • Сеттерах
  • Полях

image

image

image

Аннотация @Value

image

Тоже самое можно делать с помощью @Value.

image

Первые два шага идентичны, но внедрение осуществляем с помощью @Value. Аннотируем (помечаем) поля, в аргументы посталяем название ключа. Значение, которое лежит по этому ключу будет внедрено в соответствующее поле.

Аннотация @Scope

image

Конфигурацию области видимости мы тоже можем настроить с помощью аннотаций - для этого и существует @Scope.

image

Какие вы знаете различные scope у Spring Bean?

Spring поддерживает пять областей bean

  • singleton: ограничивает определение компонента одним экземпляром для каждого контейнера Spring IoC. Может быть создан только один экземпляр бина. Этот тип используется спрингом по умолчанию, если не указано другое. Следует осторожно использовать публичные свойства класса, т.к. они не будут потокобезопасными.
  • prototype: создается новый экземпляр при каждом запросе. Охватывает один компонент для включения любого количества экземпляров.
  • request: аналогичен prototype, но название служит пояснением к использованию бина в веб приложении. Создается новый экземпляр при каждом HTTP request.
  • session: новый бин создается в контейнере при каждой новой HTTP сессии.
  • global-session: используется для создания глобальных бинов на уровне сессии для Portlet приложений. Расширяет определение компонента до глобального HTTP.

Аннотации @PostConstruct и @PreDestroy

Есть два метода из жизненного цикла бина - init-method и destroy-method. В Spring аннотации @PostConstruct и @PreDestroy делают тоже самое.

image

image

image

Spring конфигурация с помощью Java кода

image

Аннотация @Configuration

image

image

image

image

Раньше использовали класс ClassPathXmlApplicationContext и указывали ему путь до конфигурационного xml файла. Теперь используем другой класс AnnotationConfigApplicationContext, ему на вход передаем конфигурационный класс и получаем доступ к контексту, из которого впоследствии можем получать бины.

image

@Bean

image

image

image

@PropertySource указывает путь до файла с нашими входными значениями.

Spring MVC

Spring MVC - это один из компонентов Spring Framework, который позволяет разрабатывать web приложения на Java. Spring MVC предполагает разработку web приложений с использованием архитектуры Model - View - Controller. Разрабатывая web приложения с помощью Spring MVC, мы можем использовать все, что дает нам Spring Core - бины, DI, и так далее.

image

image

image

image

Controller - это обычный Java класс, помечается аннотацией @Controller

image

image

Сервер (в нашем случае Apache Tomcat) считывает содержимое файла web.xml. То есть в этом файле мы можем прописать настройки для нашего сервера.

DispatcherServlet - класс для создания dispatcher servlet.

@GetMapping над методов в контроллере указывает какой url будет приходить в этот метод контроллера. Пример: @GetMapping("/hello-world").

Конфигурация Spring MVC приложения:

  • web.xml и applicationContext.xml
    • web.xml считывается сервером Apache Tomcat, конфигурирует DispatcherServlet.
    • applicationContext.xml - конфигурация Spring приложения (бины, component scan, настройка Thymeleaf)
  • Java код

image

image

Конфигурационный файл Spring (Java класс) помечается аннотациями:

  • @Configuration
  • @ComponentScan - принимает в аргументы путь до пакета, в котором лежат компоненты
  • @EnabeWebMVC - т.к. теперь MVC приложение, эта анноотация равноценна тэгу <mvc:annotation-driven/> в applicationContext.xml

Так же мы можем реализовать интерфейс WebMvcConfigurer, если мы хотим настроить Spring MVC под себя, например когда мы хотим использовать вмест стандартного шаблонизатора щаблонизатор Thymeleaf. Этот интерфейс обязывает реализовать метод configererViewResolvers() , в котором мы указываем необходимый шаблонизатор.

Так же с помощью Spring и @Autowired внедряем ApplicationContext. Создаем бины, которые относятся к Thymeleaf.

image

Контроллеры

image

image

image

image

image

image

image

Примечание:

  1. При каждом запросе на этот метод контроллера в параметре request будет лежать объект, который представляет собой http запрос. Из этого http запроса с помощью вызова метода getParameter() и параметром этого метода, который равен названию ключа, мы можем получить значение параметра из GET запроса.
  2. @RequestParam используется в методах контроллера, применяется к аргументам метода, принимает себе в аргументы название ключа того параметра, который ожидаем в URL. Spring сам возьмет этот параметр из URL и сам положит его в аргумет метода name. В отличии от HttpServletRequest, который при GET запросе кладет в параметны null, @RequestParam при запросе без параметров выдает ошибку.

image

что бы избежать ошибки при запросе без параметров, можно использовать такую конструкцию :

image

required = false означает, что если мы передаем праваметры в запросе, то они внедряются в переменные аргумента, если же не передаем параметры в URL, то в этих переменнах будет лежать null.

image

image

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

image

image

image

image

Это URL по стандартам. Хоть сущность называется в единственном числе - Post, но при запросе GET мы получаем все все записи для этой сущности, поэтому URL во множественном числе - /posts.

image

image

image

image

image

image

{id} означает, что в эти скобки при запуске мы сможем поместить любое число и оно поместится в аргументы метода @PathVariable - извлекает значение из URL, в этом примере id из запроса поместится в аргументы метода

image

У формы есть атрибуты method и action.

В method пиется тот http метод, который будет использоваться при отправки этой формы. В action пишется адрес, на который будут отправляться данные с этой формы. В данном случае, если мы нажмем Add Person, то данные будут отправлены методом POST на адрес /people.

Тег <label> дает понять пользователю что вводить в это поле, т.е. помечают поля, что именно надо вводить (Name, Surname, Email). for="" в теге <label> указывает принадлежность к <input/>, в for="" нужно писать то, что указано в id="" в <input/>.

Тег <input/> создает поле для ввода.

type="text" - говорит, что поле будет текстовым.

type="submit" - говорит, что это кнопка и при нажатии на нее, все данные будут отправлены.

image

image

HTML формы в Thymeleaf очень похожи на обычные HTML формы, но есть свои дополнительные функции:

  • HTML формы в Thymeleaf принимают на вход объект, для которого эта форма создана, т.е. если мы хотим создать форму для человека (просто пример), мы должны в контроллере, который будет отдавать шаблон с этой формы, в модель поместить нового пустого человека, и в шаблоне мы должны получать доступ к этому объекту класса Person, у которого не назначены значения полей.

image

@ModelAttribute работает по разному в зависимости от того, что она аннотирует.

image

В данном случае в каждом методе текущего контроллера мы хотим добавить пару ключ-значение, т.е. в каждой моделе в методе index, в методе show и в методе newPerson по умолчанию была пара ключ-значение с ключом = "headerMessage" и значением = "Welcome to our website!".

image

image

Все те вещи, которые в первом случае делаются вручную (первый блок кода) : создание нового объекта, добавление значений этой объекту с помощью сеттеров, добавление созданного объекта в модель. Все эти вещи берет на себя @ModelAttribute, которая аннотирует аргумент метода. Т.е. отправив POST запрос на этот метод контроллера, в аргументе Person person уже будет лежать объект класса Person с полями, которые были заданы значаниями из html формы. И этот объект класса Person уже будет помещен в модель.

image

image

У HTTP есть много разных методов, но у HTML 5 только два. И HTML 5 является стандаротом и все браузеры работают с ним, соответственно, когда мы пишем HTML код, мы можем использовать только GET и POST метода.

image

Это форма для обновления существующей сущности (человека), и запрос должен осуществляться с помощью PATCH запроса. Скрытое поле - это обычное поле, просто мы не видим его в браузере и не можем поменять его значение с помощью браузера. type="hidden" - означает скрытое поле. Если мы используем Thymeleaf, то он сам создает за нас это скрытое поле, сами мы его не создаем.

image

Тут мы используем метод Thymeleaf.

image

Вот так выглядит фильтр в коде:

image

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

Валидация форм. Аннотация @Valid

Для валидирования значений нужно импортировать зависимость Hibernate Validator Engine. Помечаем поля модели аннотациями валидации :

  • @NotEmpty
  • @Size
  • @Min
  • @Max
  • @Email
  • и другие

Значения, которые приходят из форм обрабатываются в контроллере. И что бы эти значения из формы валидироались нужно поставить @Valid на модель, теперь на этапе внедрения значений в объект @Valid будет проверять эти значения на условия, которые были заданы в классе сущности. Если условия нарушаются, то пояляется ошибка, и эта ошибка помещается в отдельный объект BindingResult. ВАЖНО! Объект BindingResult должен всегда идти всегда сразу после модели, которая валидируется. У этого объекта с ошибками есть специальный метод hasErrors(), который говорит есть ли ошибки в BindingResult.

image

Spring Validator

Если на поле в таблице БД стоит ограничение уникальности, то при повторном вводе существующего значения будет ошибка. Мы Должны обращаться к БД и проверять есть ли там уже такое значение или нет, что бы красиво обрабатывать эти ошибки у Spring есть специальный интерфейс Validator. Для использования Spring Validator создается отдельный класс для каждой сущности, и обычно эти классы лежать в папке проекта util. Мы должны реализовать два метода интерфейса Validator: supports() и validate(). В методе supports() мы должны указать Spring к какому классу этот валидатор относится, т.е. на объектах какого класса этот валидатор можно использовать. Метод validate() вызывается в контроллере на объекте, который приходит с формы. В аргументах этого метода объекта класса Object, т.к. этот интерфейс должен быть универсальным для всех, поэтому даункастим object до объекта нашего класса, для которого делаем валидатор.

image

После создания валидатора можно использовать его в контроллере, для этого внедряем его и вызываем метод validate() в тех методах, где нужна проверка. Первым аргументом в этот метод подается объект пришедший с формы, вторым - BindingResult.

image

теперь если придет невалидное знаечние из формы, то ошибка поместится в BindingResult, а эти ошибки обрабатываются на стороне представления.

Валидация паттернов

@Pattern позволяет проверить строку на соответствие паттерну.

image

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

Spring Boot

image

image

image

image

image

image

image

https://start.spring.io/ - сайт для создания пустого Spring Boot приложения. Тут можно выбрать язык програмирования, сборщик, версию Spring Boot, как приложение будет собираться : jar / war, версию java, выбрать зависимости (стартер) : Spring Web, Thymeleaf и т.д. Жмем Generate, скачивается файл, его нужно разархивировать и открыть в среде разработки.

@SpringBootApplication - главная аннотация в Spring Boot, помечает класс, который запускает приложение - конфигурационный файл. Эта аннотация проводит автоконфигурацию приложения, настраивает сканирование компонентов и т.д., т.е. одна делает все за другие аннотации, такие как : @ComponentScan, @Configuration и т.д. Если класс помечен аннотацией @Component, то благодаря этой аннотации он будет отсканирован и будет создан бин этого класса. В этой аннотации ComponentScan настроен таким образом, что он будет сканировать все файлы в этой папке и во всех подпапках. Класс помеченный аннотацией @SpringBootApplication должен находится в конре нашего проекта, все остальные классы должны находиться на одном с ним уровне, либо на уровень ниже.

image

SpringApplication - специальный класс, на котором вызывается метод run и ему передается текущий класс. С помощью метода run запускается встроенный сервер и нае Spring приложение.

Файл application.properties автоматически просматривается Spring Boot , в нем помещаем конфигурацию Sprong Boot приложения. Информация в этом файле лежит в формате ключ-значение. Например:

image

так же тут конфигурируются Security, Spring Data JPA, Hibernate, БД и т.д.

Или так, например:

image

Spring Security

image

image

image

image

image

Когда мы хотим реализовать аутентификацию в Spring Security, мы должны создать класс, который реализует интерфейс AuthenticationProvider, в этом интерфейсе есть одна сигнатура authenticate, в реализации этого метода мы описываем логику аутентификации пользователя. Этому методу на вход подается объект Authetication и возвращает это метод тоже объект Authetication. То есть этот объект несет в себе логин и пароль пользователя (credentials на схеме выше), когда он пытается аутентифицироваться. Principal - объект, который получается на выходе и несет в себе данные о пользователе, который только что прошел успешную аутентификацию (имя, фвмилия, дата рождения и т.д.).

Т.к. у нас могут быть разные способы аутентификации (обращение к БД, обращение к стороннему серверу...), то в приложении может быть несколько AutheticationProvider'ов каждый со своей реализацией метода authenticate().

image

image

Session

image

image

image

image

Cookie

image

image

image

image

image

Spring REST

image

image

image

image

image

image

image

В JSON'е данные в виде пар ключ-значение. Мы не можем напрямую использовать JSON в нашем Java приложении, потому что это строка с ключами и значениями, в JavaScript мы можем использовать его напрямую, потому что JSON пришел из языка JavaScript, но в Java мы не можем обратиться напрямую к ключу и получить знаечние, но мы можем JSON перевести в Java объект: ключ в JSON - это поле ы Java объекте. Для того что бы конвертировать JSON в Java объекты и наоборот мы используем библиотеку Jackson.

image

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

RestTemplate - класс (из библиотеки Spring Web) для запросов к стороннему REST API сервису. У этого класса есть методы соответствующие каждому http методу : getForObject(), postForObject(), putForObject() и т.д. HttpHeaders - класс из библиотеки Spring для передачи заголовков.

Подключимся к переводчику Яндекса, и будем переводить текст, введенный пользователем в консоль.

image

Ответ:

image

ObjectMapper- класс, с чьей помощью мы можем распарсить любую строчку JSON. JsonNode - JSON, который уже был распаршен. Яндекс нам вернул массив из переводов под названием translations. Что бы получить только перевод нашего текста, а не весь JSON, получим первый элемент в этом массиве и в этом объекте получаем ключ - "text".

image

image

Обычно структура JSON'а обговаривается, которая будет передаваться и приходить, и она всегда одна, и она обычно не меняется. Обмен JSON'ами происходит много раз и что бы не парсить каждый раз через ObjectMapper, можно создать Java класс и Jackson будет автоматически JSON в объект этого Java класса.

image

Класс для каждогоэлемента массива translations: image

image

image

И теперь объект, который вернется от Яндекса мы помещаем не в String, а в объект нашего класса YandexResponse.

image

@ResponseBody - главная аннотация для создания REST приложений. Spring понимает, что мотод помеченный этой аннотацией, не возвращает название для представления, в этом методе возвращаются какие-то данны (в примере возвращается просто объект класса String). Эта аннотация говорит что не нужно искать представление с названием "Hello world!", нужно просто вернуть такую строку при переходе на адрес /api/sayHello

image

Здесь, если бы не было @ResponseBody, то Spring искал бы представление с названием "Hello world!" в папке 'templates'.

@RestController - специальная аннотация, которая сокращает количество кода. @Controller + @ResponseBody = эта аннотация означает, что каждый метод в этом контроллере имеет аннотацию @ResponseBody и ее не надо писать над методами

image

@ExceptionHandler - этой аннотацией помечается метод, который ловит исключения и возвращает необходимый JSON(объект).

image

ResponseEntity - обертка объекта response. В ResponseEntity указываем тело HTTP ответа - response и статус HttpStatus.NOT_FOUND.

Прием данных

@RequestBody

image

@RequestBody помечает параметр в методе контроллера, и когда мы пришлем JSON в этот метод, @RequestBody автоматически сконвертирует его в объект указанного класса (в нашем случае Person).

image

DTO (Data Transfer Object)

image

image

image

image

ModelMapper

ModelMapper - класс, который позволяет DTO переделывать в модель и наоборот. Необходимо недрить зависимость ModelMapper что бы использовать этот класс. Методу map() этого класса передаем исходный объект и класс, в который хотим переделать исходный объект. ModelMapper найдет все поля, которые совпадают по названию и в новый объект положит все опля из исходного объекта.

image

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

image

image

image

JWT