- Spring Core [Junior]
- Spring MVC [Junior]
- Spring Validator [Junior]
- Spring Boot [Junior]
- Spring Security [Junior]
- Spring REST [Junior]
- JWT [Junior]
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 весит всего 2 МБ памяти.
- Масштабируемость: интерфейс управления транзакциями Spring может масштабироваться как до локальной транзакции в одной базе данных, так и до глобальных транзакций с помощью модуля JTA
- Обработка исключений: Обработка исключений проста благодаря многочисленным ресурсам API для обработки исключений в каждом модуле.
- Многоуровневая архитектура: Позволяет использовать нужные части программы и отказаться от остальных.
- Включено POJO: Простое старое объектное программирование на Java обеспечивает непрерывную тестируемость и интеграцию.
- С открытым исходным кодом: Бесплатно для всех и без блокировки поставщика.
- Инверсия управления (IOC): Достигается свободная связь через IOC, позволяя объектам передавать свои зависимости другим объектам, а не зависимым объектам.
- Аспектно-ориентированный (AOP): Spring поддерживает аспектно-ориентированное программирование, парадигму, которая отделяет бизнес-логику приложений от системных служб.
Приложения Spring содержат пять компонентов:
- Интерфейс: Определяет функции программы.
- Класс компонента: Содержит свойства, методы настройки и получения для доступа к компоненту, а также определенные функции и т.д.
- Spring Аспектно-ориентированное программирование (AOP): Включает в себя сквозные функциональные возможности, которые не поддерживаются в объектно-ориентированном программировании.
- Файл конфигурации компонента: Содержит информацию о классах, способах их настройки и определяет их взаимосвязи.
- Пользовательская программа: Вызывает функции по всей программе
Application Context & Dependency Injection
Типичное Java приложение - это набор Java объектов, которые взаимодействуют друг с другом и ссылаются друг на друга.
Кргда Java приложение запускается, все необходимые Java объекты создаются и помещаются в оперативную память. В ходе работы приложения, объекты могут добавляться / удаляться. Также могут изменяться связи между объектами. Большое количество объектов и связей между ними встречается в любом более-менее сложном Java приложении. Spring помогает нам в работе с множеством объектов.
Существуют некоторые проблемы при создании приложений, например, нужно что бы конкретный объект создавался только один раз (пример Database). Можно решить это без Spring с помощью паттерна Singleton. но для этого требуется дополнительный код. Еще одна проблема, что нужно внедрять ссылку на этот единственный объект (Database) во все остальные классы, выстроить иерархию. Можно сделать вручную, но это очень сложно и запутанно.
Spring Framework дает возможность удобного и эффективного доступа к БД, предоставляет для этого множество инструментов для взаимодействия с БД. JDBC - примитивный и неудобный способ взаимодествия с БД. Он не подходит для сложных приложений, слишком низкоуровневый.
Spring MVC - компонент Spring Framework, который позволяет создавать Web - приложения. Огромное количество Web - приложений в интернете работают на Spring MVC. Помимо этого, Spring MVC часто используется в качестве backend - API для мобильных приложений.
Файл конфигурации для Spring представляет собой XML-файл, содержащий информацию о классе для проекта. Они описывают конфигурацию каждого класса, то, как они представлены другим классам, и зависимости во всей программе.
Конфигурационный файл 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> - передаем параметры для конструктора для создания бина.
Инверсия управления
Контейнер IoC создает, настраивает и соединяет объекты, одновременно управляя их жизненным циклом. Контейнер получает инструкции по этим областям из метаданных конфигурации, предоставленных пользователем.
- Контейнер BeanFactory: Этот заводской класс содержит предварительно упакованную коллекцию компонентов, которые создаются при вызове клиентами. Это самый простой контейнер для поддержки DI.
- Контейнер ApplicationContext: Построенный поверх контейнера BeanFactory, этот контейнер обеспечивает дополнительные функциональные возможности, ориентированные на предприятие. Например, контейнеры ApplicationContext предоставляют возможность разрешать текстовые сообщения и публиковать события приложения.
AOП-это метод программирования, который позволяет программистам модулировать поведение, используемое в типичных подразделениях ответственности, используемых в объектно-ориентированном программировании. Основная конструкция аспектов AOП – это поведение, применимое к разным классам. Извлечение этих моделей поведения из отдельных компонентов в аспекты позволяет легко использовать их повторно.
Это объекты, созданные из метаданных конфигурации при их передаче в контейнер IOC. Они составляют основу всех Spring. Контейнер IOC создает экземпляры, настраивает, подключает и управляет каждым компонентом. Это просто Java объект. Когда Java объекты создаются с помощью Spring'а они называются бинами (beans). Бины создаются из Java классов (так же, как и обычные объекты).
<bean id="testBean"
class="ru.kirillova.springcourse.TestBean">
<constructor-arg value="Neil"/>
</bean>MusicPlayer слабо зависит от интерфейса Music. В методе playMusic() видим, что MusicPlayer сам создает свои зависимости, даже если будем использовать Spring Framework, мы будем сами обращаться к application context'у и будем сами извлекать из него созданный бин.
Inversion of Control - это такой архитектурный подход, когда сущность не сама создает свои зависимости, а когда зависимости для этой сущности поставляются извне.
Решние этой проблемы с помощью внедрения зависимостей (Dependency Injection) с помощью Spring Framework будет рассмотрена далее.
Смотри код в папке spring-app1 или уроки №5,6, показано на практике внедрение зависимостей и создание бинов на примере MusicPlayer
- XML файл когфигурации (старый способ, но многие существующие приложения до сих пор его используют, будут рассмотрены несколько примеров далее с его использованием).
- Java аннотации и немного XML (современный способ).
- Вся конфигурация на Java коде (современный способ).
В независимой Java программе ApplicationContext можно создать следующим образом:
- AnnotationConfigApplicationContext: при использовании Spring в качестве автономного приложения можно создать, инициализировать контейнер с помощью аннотаций.
- ClassPathXmlApplicationContext: второй подход использует xml файл, в котором задаются необходимые настройки, а затем используем класс для загрузки файла и получения объекта контейнера.
- FileSystemXmlApplicationContext: аналогичен варианту с xml, но с возможностью загрузки файла конфигурации из любого места файловой системы.
Тремя наиболее популярными контейнерами являются:
- AnnotationConfigApplicationContext: Эта реализация позволяет создавать ApplicationContext на основе аннотаций конфигурации. Вы можете указать классы конфигурации, содержащие аннотации, такие как
@Configurationи@Bean, и ApplicationContext создаст бины на основе этих аннотаций. - FileSystemXmlApplicationContext: Заставляет конструктор загружать определения компонентов из файла конфигурации XML. На него должен быть указан полный путь к файлу.
- ClassPathXmlApplicationContext: Этот контейнер выполняет то же самое, что и выше, но не требует полного пути к файлу. Вместо этого вы устанавливаете свойство CLASSPATH и позволяете контейнеру находить XML по этому CLASSPATH.
- WebXmlApplicationContext: Загружает все определения компонентов в веб-приложение из XML-файла.
- AnnotationConfigWebApplicationContext: Эта реализация предназначена для веб-приложений и позволяет создавать ApplicationContext на основе аннотаций конфигурации. Она автоматически обнаруживает классы конфигурации, используемые в вашем веб-приложении, и создает бины на основе этих аннотаций.
BeanFactory – это базовый, компактный контейнер с ограниченной функциональностью. Его лучше всего использовать для простых задач или при использовании машин с низким ресурсом. ApplicationContext – это расширенный, более интенсивный контейнер с расширенным интерфейсом и дополнительными возможностями, такими как AOP. Этот контейнер лучше всего использовать, когда вам требуется больше функциональности, чем на заводе Bean, и у вас достаточно ресурсов, доступных на машине.
- Создаем Java классы (будущие бины)
- Создаем и связываем бины с помощью Spring (аннотации, XML или Java код)
- При использовании, все объекты (бины) берутся из контейнера Spring
Внедрение зависимостей (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)
Scope задает то, как Spring будет создавать ваши бины. Есть такой scope, который называется Singleton, он используется по умолчанию. Singleton - это паттерн программирования.
Если не указывать scope, то по умолчанию Singleton:
<bean id="musicBean"
class="ru.kirillova.springcourse.ClassicalMusic">
</bean>- По умолчанию создается один объект (он создается до вызова метода
getBean()). - При всех вызовах
getBean()возвращается ссылка на один и тот же единственный объект.
Scope Singleton чаще всего используется тогда, когда у нашего бина нет изменяемых состояний (stateless). Потому что если будем изменять состояние у Singleton бина, столкнемся с проблемой.
Здесь видим, что среда разработки говорит, что Singleton используется по умолчанию, и указывать его явно нет смысла.
Еще один scope, который называется Prototype, каждый раз создает новый объект при вызове getBean(). Используется, когда у бина есть изменяемые состояния (stateful).
Другие scope'ы , такие как request, session, flobal-session, будут изучены в разделе Spring MVC.
смотри код в папке 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. Таким образом все публичные переменные класса могут быть изменены одновременно из разных мест. Так что — нет, не является. Однако поменяв область действия бина на request, prototype, session он станет потокобезопасным, но это скажется на производительности.
Внутренний компонент используется как свойство другого компонента. Внутренние компоненты могут быть определены в XML-файле конфигурации либо в элементах <property>, либо <constructor-arg>. Все внутренние компоненты всегда имеют область действия как prototype и не имеют идентификаторов.
Это функция Spring, которая позволяет контейнеру Spring автоматически устанавливать отношения зависимостей между сотрудничающими компонентами, просматривая BeanFactory. Автоматическая проводка может быть настроена для определения этих отношений с использованием имен компонентов, типов или даже конструкторов классов.
init-method, destroy-method, factory method
init-method
Это метод, который запускается в ходе инициализации бина. Используется для инициализации ресурсов, обращения к внешним файлам, запуска БД.
destroy-method
Этот метод, который запускается в ходе уничтожения бина (при завершении приложения). В этом методе обычно происходит очищение ресурсов, закрытие потоков ввода-выводы, закрытие доступа к БД.
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.
- У нас есть 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 никогда не работает.
- Из этого контейнера выходят полностью настроенные бины.
- Позволяет настраивать наши бины до того, как они попадают в контейнер.
- У этого интерфейса 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- для работы с аннотациями
Умеет слушать контекст Spring'а, все ивенты, которые с ним происходят:
ContextStartedEvent- означает, что контекст начал свое построение.ContextStoppedEventContextRefreshedEventContextClosedEventИз любого ивента можно вытащить контекст.
Java аннотация - это специальный тип комментариев в вашем коде с помощью которых можно:
- Передавать какие-либо инструкции для Java компилятора (пример: @Override).
- Передавать какие-либо инструкции для анализаторов исходного кода.
- Передавать метаданные, которые могут быть использованы либо вашим Java приложением(с помощью рефлексии), либо другими приложениями или фреймворками (привет: Spring Framework).
- Помечаем ей класс, если хотим, чтобы Spring создал бин из этого класса.
- Именно эту аннотацию Spring ищет, когда сканирует все ваши классы.
- Можно указать
idдля создаваемого бина, можно не указывать (тогда будет названиеназвание_класса_с_маленькой_буквы).
При использовании аннотаций, ручное создание бинов в xml файле уже не актуально, нужно всего лишь сказать Spring чтобы он отсканировал все компоненты, включает эту операцию следующуя строка:
<context:component-scan base-package="ru.kirillova.springcourse" />Теперь при запуске приложения Spring отсканирует все классы в пакете springcourse и создаст бины классов, помеченных аннотацией @Component.
Сканирует все классы ClassPathDefinitionScanner и ищет все бины, которые аннотированы @Component. Этот сканер не является ни BeanPostProcessor'ом, ни BeanFactoryPostProcessor'ом. Он является ResourceLoaderAware - подгружает дополнительные ресрсы.
- ConfigurationClassPostProcessor (особый BeanFactoryPostProcessor)
- Его регистрирует AnnotationConfigApplicationContext
- Он создает бин-дифинишны по @Bean
- А так же относится к:
- @Import
- @ImportResource
- @ComponentScan
Эта аннотация осущществляет внедрение зависимостей.
Мы можем внедрять бины указывая конкретный класс, или какой-то интерфейс:
Решает проблему неоднозначности, когда для внедрения подходят несколько бинов.
Эту аннотацию можно использовать на :
- Конструкторах
- Сеттерах
- Полях
Тоже самое можно делать с помощью @Value.
Первые два шага идентичны, но внедрение осуществляем с помощью @Value. Аннотируем (помечаем) поля, в аргументы посталяем название ключа. Значение, которое лежит по этому ключу будет внедрено в соответствующее поле.
Конфигурацию области видимости мы тоже можем настроить с помощью аннотаций - для этого и существует @Scope.
Spring поддерживает пять областей bean
- singleton: ограничивает определение компонента одним экземпляром для каждого контейнера Spring IoC. Может быть создан только один экземпляр бина. Этот тип используется спрингом по умолчанию, если не указано другое. Следует осторожно использовать публичные свойства класса, т.к. они не будут потокобезопасными.
- prototype: создается новый экземпляр при каждом запросе. Охватывает один компонент для включения любого количества экземпляров.
- request: аналогичен prototype, но название служит пояснением к использованию бина в веб приложении. Создается новый экземпляр при каждом HTTP request.
- session: новый бин создается в контейнере при каждой новой HTTP сессии.
- global-session: используется для создания глобальных бинов на уровне сессии для Portlet приложений. Расширяет определение компонента до глобального HTTP.
Есть два метода из жизненного цикла бина - init-method и destroy-method. В Spring аннотации @PostConstruct и @PreDestroy делают тоже самое.
Раньше использовали класс ClassPathXmlApplicationContext и указывали ему путь до конфигурационного xml файла. Теперь используем другой класс AnnotationConfigApplicationContext, ему на вход передаем конфигурационный класс и получаем доступ к контексту, из которого впоследствии можем получать бины.
@Bean
@PropertySource указывает путь до файла с нашими входными значениями.
Spring MVC - это один из компонентов Spring Framework, который позволяет разрабатывать web приложения на Java. Spring MVC предполагает разработку web приложений с использованием архитектуры Model - View - Controller. Разрабатывая web приложения с помощью Spring MVC, мы можем использовать все, что дает нам Spring Core - бины, DI, и так далее.
Controller - это обычный Java класс, помечается аннотацией @Controller
Сервер (в нашем случае Apache Tomcat) считывает содержимое файла web.xml. То есть в этом файле мы можем прописать настройки для нашего сервера.
DispatcherServlet - класс для создания dispatcher servlet.
@GetMapping над методов в контроллере указывает какой url будет приходить в этот метод контроллера.
Пример: @GetMapping("/hello-world").
- web.xml и applicationContext.xml
- web.xml считывается сервером Apache Tomcat, конфигурирует DispatcherServlet.
- applicationContext.xml - конфигурация Spring приложения (бины, component scan, настройка Thymeleaf)
- Java код
Конфигурационный файл Spring (Java класс) помечается аннотациями:
- @Configuration
- @ComponentScan - принимает в аргументы путь до пакета, в котором лежат компоненты
- @EnabeWebMVC - т.к. теперь MVC приложение, эта анноотация равноценна тэгу
<mvc:annotation-driven/>в applicationContext.xml
Так же мы можем реализовать интерфейс WebMvcConfigurer, если мы хотим настроить Spring MVC под себя, например когда мы хотим использовать вмест стандартного шаблонизатора щаблонизатор Thymeleaf. Этот интерфейс обязывает реализовать метод configererViewResolvers() , в котором мы указываем необходимый шаблонизатор.
Так же с помощью Spring и @Autowired внедряем ApplicationContext. Создаем бины, которые относятся к Thymeleaf.
Примечание:
- При каждом запросе на этот метод контроллера в параметре
requestбудет лежать объект, который представляет собой http запрос. Из этого http запроса с помощью вызова методаgetParameter()и параметром этого метода, который равен названию ключа, мы можем получить значение параметра из GET запроса. - @RequestParam используется в методах контроллера, применяется к аргументам метода, принимает себе в аргументы название ключа того параметра, который ожидаем в URL. Spring сам возьмет этот параметр из URL и сам положит его в аргумет метода
name. В отличии отHttpServletRequest, который при GET запросе кладет в параметны null, @RequestParam при запросе без параметров выдает ошибку.
что бы избежать ошибки при запросе без параметров, можно использовать такую конструкцию :
required = false означает, что если мы передаем праваметры в запросе, то они внедряются в переменные аргумента, если же не передаем параметры в URL, то в этих переменнах будет лежать null.
метод addAttribute() - специальный метод, с помощью которого мы можем положить в модель пару ключ-значение, эта модель будет отправлена на представление, где с помощью шаблонизатора мы сможем получить значения по ключу.
Это URL по стандартам. Хоть сущность называется в единственном числе - Post, но при запросе GET мы получаем все все записи для этой сущности, поэтому URL во множественном числе - /posts.
{id} означает, что в эти скобки при запуске мы сможем поместить любое число и оно поместится в аргументы метода
@PathVariable - извлекает значение из URL, в этом примере id из запроса поместится в аргументы метода
У формы есть атрибуты method и action.
В method пиется тот http метод, который будет использоваться при отправки этой формы. В action пишется адрес, на который будут отправляться данные с этой формы. В данном случае, если мы нажмем Add Person, то данные будут отправлены методом POST на адрес /people.
Тег <label> дает понять пользователю что вводить в это поле, т.е. помечают поля, что именно надо вводить (Name, Surname, Email). for="" в теге <label> указывает принадлежность к <input/>, в for="" нужно писать то, что указано в id="" в <input/>.
Тег <input/> создает поле для ввода.
type="text" - говорит, что поле будет текстовым.
type="submit" - говорит, что это кнопка и при нажатии на нее, все данные будут отправлены.
HTML формы в Thymeleaf очень похожи на обычные HTML формы, но есть свои дополнительные функции:
- HTML формы в Thymeleaf принимают на вход объект, для которого эта форма создана, т.е. если мы хотим создать форму для человека (просто пример), мы должны в контроллере, который будет отдавать шаблон с этой формы, в модель поместить нового пустого человека, и в шаблоне мы должны получать доступ к этому объекту класса
Person, у которого не назначены значения полей.
@ModelAttribute работает по разному в зависимости от того, что она аннотирует.
В данном случае в каждом методе текущего контроллера мы хотим добавить пару ключ-значение, т.е. в каждой моделе в методе index, в методе show и в методе newPerson по умолчанию была пара ключ-значение с ключом = "headerMessage" и значением = "Welcome to our website!".
Все те вещи, которые в первом случае делаются вручную (первый блок кода) : создание нового объекта, добавление значений этой объекту с помощью сеттеров, добавление созданного объекта в модель.
Все эти вещи берет на себя @ModelAttribute, которая аннотирует аргумент метода. Т.е. отправив POST запрос на этот метод контроллера, в аргументе Person person уже будет лежать объект класса Person с полями, которые были заданы значаниями из html формы. И этот объект класса Person уже будет помещен в модель.
У HTTP есть много разных методов, но у HTML 5 только два. И HTML 5 является стандаротом и все браузеры работают с ним, соответственно, когда мы пишем HTML код, мы можем использовать только GET и POST метода.
Это форма для обновления существующей сущности (человека), и запрос должен осуществляться с помощью PATCH запроса.
Скрытое поле - это обычное поле, просто мы не видим его в браузере и не можем поменять его значение с помощью браузера.
type="hidden" - означает скрытое поле.
Если мы используем Thymeleaf, то он сам создает за нас это скрытое поле, сами мы его не создаем.
Тут мы используем метод Thymeleaf.
Вот так выглядит фильтр в коде:
т.е. мы сами не реализуем фильтр, он уже есть в Spring, мы просто его добавляем к нашему приложению.
Для валидирования значений нужно импортировать зависимость Hibernate Validator Engine. Помечаем поля модели аннотациями валидации :
- @NotEmpty
- @Size
- @Min
- @Max
- и другие
Значения, которые приходят из форм обрабатываются в контроллере. И что бы эти значения из формы валидироались нужно поставить @Valid на модель, теперь на этапе внедрения значений в объект @Valid будет проверять эти значения на условия, которые были заданы в классе сущности. Если условия нарушаются, то пояляется ошибка, и эта ошибка помещается в отдельный объект BindingResult. ВАЖНО! Объект BindingResult должен всегда идти всегда сразу после модели, которая валидируется.
У этого объекта с ошибками есть специальный метод hasErrors(), который говорит есть ли ошибки в BindingResult.
Если на поле в таблице БД стоит ограничение уникальности, то при повторном вводе существующего значения будет ошибка. Мы Должны обращаться к БД и проверять есть ли там уже такое значение или нет, что бы красиво обрабатывать эти ошибки у Spring есть специальный интерфейс Validator. Для использования Spring Validator создается отдельный класс для каждой сущности, и обычно эти классы лежать в папке проекта util. Мы должны реализовать два метода интерфейса Validator: supports() и validate().
В методе supports() мы должны указать Spring к какому классу этот валидатор относится, т.е. на объектах какого класса этот валидатор можно использовать.
Метод validate() вызывается в контроллере на объекте, который приходит с формы. В аргументах этого метода объекта класса Object, т.к. этот интерфейс должен быть универсальным для всех, поэтому даункастим object до объекта нашего класса, для которого делаем валидатор.
После создания валидатора можно использовать его в контроллере, для этого внедряем его и вызываем метод validate() в тех методах, где нужна проверка. Первым аргументом в этот метод подается объект пришедший с формы, вторым - BindingResult.
теперь если придет невалидное знаечние из формы, то ошибка поместится в BindingResult, а эти ошибки обрабатываются на стороне представления.
@Pattern позволяет проверить строку на соответствие паттерну.
В аргументы этой аннотации подается регулярное выражение, которому должна соответствовать проверяемая строка, и сообщение об ошибке, если строка не пройдет проверку.
https://start.spring.io/ - сайт для создания пустого Spring Boot приложения.
Тут можно выбрать язык програмирования, сборщик, версию Spring Boot, как приложение будет собираться : jar / war, версию java, выбрать зависимости (стартер) : Spring Web, Thymeleaf и т.д.
Жмем Generate, скачивается файл, его нужно разархивировать и открыть в среде разработки.
@SpringBootApplication - главная аннотация в Spring Boot, помечает класс, который запускает приложение - конфигурационный файл. Эта аннотация проводит автоконфигурацию приложения, настраивает сканирование компонентов и т.д., т.е. одна делает все за другие аннотации, такие как : @ComponentScan, @Configuration и т.д. Если класс помечен аннотацией @Component, то благодаря этой аннотации он будет отсканирован и будет создан бин этого класса. В этой аннотации ComponentScan настроен таким образом, что он будет сканировать все файлы в этой папке и во всех подпапках.
Класс помеченный аннотацией @SpringBootApplication должен находится в конре нашего проекта, все остальные классы должны находиться на одном с ним уровне, либо на уровень ниже.
SpringApplication - специальный класс, на котором вызывается метод run и ему передается текущий класс. С помощью метода run запускается встроенный сервер и нае Spring приложение.
Файл application.properties автоматически просматривается Spring Boot , в нем помещаем конфигурацию Sprong Boot приложения. Информация в этом файле лежит в формате ключ-значение.
Например:
так же тут конфигурируются Security, Spring Data JPA, Hibernate, БД и т.д.
Или так, например:
Когда мы хотим реализовать аутентификацию в Spring Security, мы должны создать класс, который реализует интерфейс AuthenticationProvider, в этом интерфейсе есть одна сигнатура authenticate, в реализации этого метода мы описываем логику аутентификации пользователя. Этому методу на вход подается объект Authetication и возвращает это метод тоже объект Authetication. То есть этот объект несет в себе логин и пароль пользователя (credentials на схеме выше), когда он пытается аутентифицироваться. Principal - объект, который получается на выходе и несет в себе данные о пользователе, который только что прошел успешную аутентификацию (имя, фвмилия, дата рождения и т.д.).
Т.к. у нас могут быть разные способы аутентификации (обращение к БД, обращение к стороннему серверу...), то в приложении может быть несколько AutheticationProvider'ов каждый со своей реализацией метода authenticate().
В JSON'е данные в виде пар ключ-значение. Мы не можем напрямую использовать JSON в нашем Java приложении, потому что это строка с ключами и значениями, в JavaScript мы можем использовать его напрямую, потому что JSON пришел из языка JavaScript, но в Java мы не можем обратиться напрямую к ключу и получить знаечние, но мы можем JSON перевести в Java объект: ключ в JSON - это поле ы Java объекте. Для того что бы конвертировать JSON в Java объекты и наоборот мы используем библиотеку Jackson.
Для всех полей Java класса должны быть сеттеры и геттеры, потому что Jackson работает именно с ними.
RestTemplate - класс (из библиотеки Spring Web) для запросов к стороннему REST API сервису. У этого класса есть методы соответствующие каждому http методу : getForObject(), postForObject(), putForObject() и т.д.
HttpHeaders - класс из библиотеки Spring для передачи заголовков.
Подключимся к переводчику Яндекса, и будем переводить текст, введенный пользователем в консоль.
Ответ:
ObjectMapper- класс, с чьей помощью мы можем распарсить любую строчку JSON.
JsonNode - JSON, который уже был распаршен.
Яндекс нам вернул массив из переводов под названием translations.
Что бы получить только перевод нашего текста, а не весь JSON, получим первый элемент в этом массиве и в этом объекте получаем ключ - "text".
Обычно структура JSON'а обговаривается, которая будет передаваться и приходить, и она всегда одна, и она обычно не меняется. Обмен JSON'ами происходит много раз и что бы не парсить каждый раз через ObjectMapper, можно создать Java класс и Jackson будет автоматически JSON в объект этого Java класса.
Класс для каждогоэлемента массива translations: 
И теперь объект, который вернется от Яндекса мы помещаем не в String, а в объект нашего класса YandexResponse.
@ResponseBody - главная аннотация для создания REST приложений. Spring понимает, что мотод помеченный этой аннотацией, не возвращает название для представления, в этом методе возвращаются какие-то данны (в примере возвращается просто объект класса String). Эта аннотация говорит что не нужно искать представление с названием "Hello world!", нужно просто вернуть такую строку при переходе на адрес /api/sayHello
Здесь, если бы не было @ResponseBody, то Spring искал бы представление с названием "Hello world!" в папке 'templates'.
@RestController - специальная аннотация, которая сокращает количество кода. @Controller + @ResponseBody = эта аннотация означает, что каждый метод в этом контроллере имеет аннотацию @ResponseBody и ее не надо писать над методами
@ExceptionHandler - этой аннотацией помечается метод, который ловит исключения и возвращает необходимый JSON(объект).
ResponseEntity - обертка объекта response. В ResponseEntity указываем тело HTTP ответа - response и статус HttpStatus.NOT_FOUND.
@RequestBody
@RequestBody помечает параметр в методе контроллера, и когда мы пришлем JSON в этот метод, @RequestBody автоматически сконвертирует его в объект указанного класса (в нашем случае Person).
ModelMapper - класс, который позволяет DTO переделывать в модель и наоборот. Необходимо недрить зависимость ModelMapper что бы использовать этот класс. Методу map() этого класса передаем исходный объект и класс, в который хотим переделать исходный объект. ModelMapper найдет все поля, которые совпадают по названию и в новый объект положит все опля из исходного объекта.
Этот способ обычно используется много раз в разных местах в приложении, и что бы не создавать каждый раз новый объект можно создать бин в конфигурационном файле приложения и внедряем его с помощью Spring в контроллер.

















































































































































