Главная страница
Навигация по странице:

  • 10. ПРАКТИЧЕСКАЯ РАБОТА № 10 Цель работы

  • 10.1. Теоретическая часть

  • 10.3. Варианты индивидуального задания

  • 11. ПРАКТИЧЕСКАЯ РАБОТА № 11 Цель работы Разобраться с использованием Spring boot. 11.1. Теоретическая часть

  • 12. ПРАКТИЧЕСКАЯ РАБОТА № 12 Цель работы Работа с жизненным циклом компонентов. Аннотации PostConstruct, PreDestroy. 12.1. Теоретическая часть

  • 13. ПРАКТИЧЕСКАЯ РАБОТА № 13 Цель работы Конфигурирование приложения. Environment. 13.1. Теоретическая часть

  • 14. ПРАКТИЧЕСКАЯ РАБОТА № 14 Цель работы Знакомство со Spring MVC. Работа с Rest API в Spring. 14.1. Теоретическая часть

  • Методичка java. Методичка По Шаблонам Java. Практикум для студентов, обучающихся по направлению подготовки 09. 03. 04 Программная инженерия


    Скачать 1.94 Mb.
    НазваниеПрактикум для студентов, обучающихся по направлению подготовки 09. 03. 04 Программная инженерия
    АнкорМетодичка java
    Дата18.05.2023
    Размер1.94 Mb.
    Формат файлаpdf
    Имя файлаМетодичка По Шаблонам Java.pdf
    ТипПрактикум
    #1142180
    страница3 из 5
    1   2   3   4   5
    9. ПРАКТИЧЕСКАЯ РАБОТА № 9
    Цель работы
    Знакомство с системой сборки приложения. Gradle.
    9.1. Теоретическая часть
    Разработка – сложный процесс, и все монотонные процессы так или иначе автоматизируются для того, чтобы программист думал о бизнес-логике, а не об инфраструктуре приложения. Сборка приложения, работа с зависимостями также автоматизирована, и для этого используются системы сборки приложений. Основные функции данных систем:
    1) организация механизма сборки приложения из исходного кода;
    2) управление зависимостями;
    3) предоставление механизмов для настройки алгоритма сборки приложения.
    Для Java наиболее известными системами сборки приложений являются
    Maven и Gradle.
    Maven
    Maven основан на использовании xml файла, в котором описывается вся нужная для сборщика приложения информация: зависимости, плагины для изменения сборки, версия самого приложения и версия Java, дополнительная информация.
    Gradle
    Gradle основан на groovy файле build.gradle, в котором также описывается основная информация. На рисунке 24 приведен пример build.gradle.

    Рисунок 24 – Пример build.gradle
    Рассмотрим основные части данного файла (рисунки 25-32).
    Рисунок 25 – Пример build.gradle, часть 1

    В plugins описаны все плагины – специальные дополнения, которые отвечают как за управление зависимостями, так и изменяют алгоритм сборки приложения, а также добавляют различные Gradle Tasks. Что такое Gradle
    Tasks будет пояснено далее.
    Рисунок 26 – Пример build.gradle, часть 2
    Далее описываются различные конфигурации: название группы пакетов, версия приложения, версия Java, дополнительные конфигурации.
    Рисунок 27 – Пример build.gradle, часть 3
    В repositories описываются репозитории – хранилища, откуда будут загружаться зависимости.
    Рисунок 28 – Пример build.gradle, часть 4

    Далее описываются непосредственно сами зависимости. Есть много типов видимости для зависимостей, вот лишь самые основные:
    – implementation – зависимость на этапе компиляции, также предоставляется как библиотека для использования на этапе runtime;
    – compileOnly – зависимость только на этапе компиляции;
    – runtimeOnly – зависимость только на этапе runtime;
    – testImplementation – implementation для запуска тестов;
    – annotationProcessor – использование процессора аннотаций.
    Часто требуется как-то кастомизировать процесс сборки приложения.
    Для этого в Gradle используются задачи Gradle Tasks. По сути, Gradle task – просто groovy script, который запускается, когда ты его вызываешь. Но удобство в том, что можно строить любые цепочки задач для сборки приложений, а также использовать задачи из плагинов или стандартные задачи Gradle.
    Рисунок 29 – Пример build.gradle, часть 5
    Ниже приведен вывод при запуске данной задачи.
    Рисунок 30 – Пример build.gradle, часть 6
    Далее приведен пример простой цепочки из задач.

    Рисунок 31 – Пример build.gradle, часть 7
    Результат выполнения задачи:
    Рисунок 32 – Пример build.gradle, часть 8
    Gradle – простой и невероятно удобный инструмент для сборки приложений, и обязательно стоит научиться им пользоваться, познать его силу и удобство.
    9.2. Задание
    Создать приложение, которое выводит какое-то сообщение в консоль.
    Создать Gradle Task, который создает jar-файл приложения, переносит его в отдельную папку, в которой хранится Dockerfile для jar, а затем создает Docker контейнер из данного jar-файла и запускает его.

    10. ПРАКТИЧЕСКАЯ РАБОТА № 10
    Цель работы
    Введение в Spring. Container. Bean. Внедрение зависимостей, основанных на конструкторах и сеттерах. Конфигурация бинов.
    Автоматическое обнаружение и связывание классов.
    10.1. Теоретическая часть
    В прошлом разрабатываемое приложение практически не обновлялось.
    Например, игры на телефоны – они выходили один раз, и никто не создавал различные дополнения, патчи для них. В те времена задумываться о поддержке разрабатываемого приложения не имело смысла, но сейчас поддержка кода имеет чрезвычайно огромное значение. Чем больше кода, тем сложнее его поддерживать, с каждой строкой кода растет технический долг приложения.
    Технический долг приложения – значение стоимости внедрения какого- то дополнительного функционала в существующий проект. Чем больше, сложнее система, тем сложнее добавлять новые фичи, и может доходить до такого, что добавление простейшей логики станет невыполнимой задачей просто из-за объема текущей логики. Поэтому требуется создавать такой код, который будет приносить минимальное количество технического долга.
    Нужно писать такой код, в котором отдельные элементы будут максимально независимы для упрощения изменения отдельной части логики. В этом и помогает нам инверсия контроля (IoC).
    Инверсия контроля – принцип, при котором управление отдельными элементами программы передается отдельному контейнеру. Лучшая фраза, что описывает инверсию контроля, это «Don’t call us, we call you». Отдельный элемент программы, в нашем случае объект, не выбирает, какой объект он будет использовать в своей логике – за это отвечает некий контейнер, который и предоставляет нужный объект.

    Наиболее известной реализацией инверсии контроля является инъекция
    зависимостей (Dependency Injection (DI)) – шаблон, в котором контейнер производит инъекцию требуемых зависимостей (объектов) в свойства другого объекта, которому требуются некие зависимости. Допустим, у нас есть класс человека «Костя», которому нужны штаны, и есть интерфейс штанов и несколько имплементаций. У «Кости» есть метод walk, в котором он выводит в консоль класс штанов, которые надел. Но мы не хотим, чтобы «Костя» сам выбирал, какие штаны ему носить. Нам нужен некий посредник, который определит, какие штаны носить «Косте», создаст нужный объект и произведет инъекцию объекта штанов «Косте»: class Kostya { private Trousers trousers; public void walk() {
    System.out.println("I'm wearing " + trousers.getName());
    } public void setTrousers(Trousers trousers) { this.trousers = trousers;
    }
    } interface Trousers {
    String getName();
    } class Joggers implements Trousers{
    @Override public String getName() { return "Joggers!";
    }
    } class Pantaloons implements Trousers {
    @Override public String getName() { return "Pantaloons....";
    }

    }
    И здесь нам пригодится как раз некий контекст, который и произведет инъекцию зависимостей. Здесь на сцену и выходит Spring, точнее, Spring Core с IoC.
    Bean (бин)
    В Spring есть понятие Bean (бин). Bean – это объект, зависимостями и жизненным циклом которого управляет Spring. У Spring существует некий контекст – ApplicationContext, который содержит множество бинов, которые мы хотим использовать. Он управляет ими и производит инъекцию зависимостей там, где требуется.
    Но нам нужно как-то объяснить контексту, какие бины мы хотим создать. Для этого нам нужно написать некую конфигурацию с разными бинами. Далее будет приведен пример с Java конфигурацией, так как на данный момент она является стандартом де-факто практически везде, но также конфигурацию можно писать и на Groovy, и при помощи xml файла, и с использованием Kotlin DSL.
    Опишем нашу конфигурацию и решим, что «Костя» будет носить джоггеры:
    @Configuration public class BeanConfig {
    @Bean public Trousers trousers() { return new Joggers();
    }
    @Bean public Kostya kostya(Trousers trousers) {
    Kostya kostya = new Kostya(); kostya.setTrousers(trousers); return kostya;
    }

    Аннотация Configuration показывает, что данный класс является конфигурацией для бинов. Аннотация Bean означает, что то, что возвращает данный метод, является бином.
    Также можно определить область видимости (scope) бина. Существует много видов областей видимости, сейчас мы ограничимся лишь двумя
    (singleton и prototype):
    1) singleton – создается только один бин и используется для всех остальных. Да, вам не нужно вручную писать логику для того, чтобы класс был синглтоном, об этом позаботится Spring;
    2) prototype – может иметь любое количество инстансов. Создается каждый раз новый бин.
    Определить область видимости можно при помощи аннотации Scope.
    Вот пример:
    @Bean
    @Scope("prototype") public Trousers trousers() { return new Joggers();
    }
    Но по умолчанию создается синглтон, что нам и требуется. Поэтому нам не нужно нигде использовать аннотацию Scope.
    Теперь попробуем получить бин «Кости» и вызвать его метод walk:
    ApplicationContext context = new
    AnnotationConfigApplicationContext(BeanConfig.class);
    Kostya kostya = context.getBean(Kostya.class); kostya.walk();
    И вывод:
    I’m wearing Joggers!
    Process finished with exit code 0
    Контекст увидел, что мы создали джоггеры, и сам произвел инъекцию их в бин. Но каждый раз для каждого бина писать где-то в конфигурации метод неудобно, gоэтому у Spring существует такое понятие, как

    ComponentScan. Context сам пробегается по пакету, ищет классы, помеченные специальными аннотациями, и создает их бины. Изменим код нашего приложения для автоматического сканирования. Для начала уберем бины из конфигурации и добавим аннотацию:
    @Configuration
    @ComponentScan public class BeanConfig {
    }
    Теперь нам нужно как-то пометить нужные классы, чтоб создались их бины. Для этого можно использовать аннотацию Component. Поставим аннотацию над классом «Панталон» и «Костя». Но нам требуется также как- то сообщить, что мы хотим добавить зависимость. Контекст же должен как-то понять, нужно ли в данное свойство производить инъекцию. Для этого используется аннотация Autowired. Но где ее ставить: над сеттером, над свойством, над конструктором, может вообще над классом?
    Существуют различные способы инъекции, рассмотрим каждый из них:
    1) через свойство (field injection) – ставим аннотацию над свойством и производится инъекция. Не особо рекомендуется для использования, хотя вполне можно так делать;
    2) через сеттер – аннотация над сеттером; данный сеттер вызывается для инъекции бина.
    Пример внедрении зависимости через сеттер:
    @Component public class Kostya { private Trousers trousers; public void walk() {
    System.out.println("I'm wearing " + trousers.getName());
    }
    @Autowired public void setTrousers(Trousers trousers) { this.trousers = trousers;

    }
    }
    3) через конструктор – наиболее удобный способ инъекции, можно даже не писать аннотацию, достаточно лишь создать конструктор с параметром, который нужно получить.
    Пример через конструктор:
    @Component public class Kostya { private final Trousers trousers; public Kostya(Trousers trousers) { this.trousers = trousers;
    } public void walk() {
    System.out.println("I'm wearing " + trousers.getName());
    }
    }
    Также добавим аннотацию для панталон и запустим наш код:
    @Component public class Pantaloons implements Trousers {
    @Override public String getName() { return "Pantaloons....";
    }
    }
    Вывод:
    I’m wearing Pantaloons...
    Process finished with exit code 0
    Для того, чтобы лучше понять Spring, рекомендуется сайт baeldung.com, а также официальная документация Spring.

    10.2. Задание
    Создать приложение, в котором создается ApplicationContext и из него берётся бин с названием, переданным в качестве аргумента к приложению, и вызывается метод интерфейса, который он имплементирует. Нужно создать по одному бину для каждого класса, определить им название. Проверить, что вызывается при вводе названия каждого из бинов. Классы и интерфейс определяются в соответствии с вариантом индивидуального задания.
    10.3. Варианты индивидуального задания
    1) Интерфейс Knight с методом void fight(), его имплементации:
    StrongKnight, WeakKnight, KingOfKnights.
    2) Интерфейс Magican с методом doMagic(), его имплементации:
    Voldemort, HarryPotter, RonWeesly.
    3) Интерфейс Programmer с методом doCoding(), его имплементации:
    Junior, Middle, Senior.
    4) Интерфейс Lighter с методом doLight(), его имплементации: Lamp,
    Flashlight, Firefly.
    5) Интерфейс Musician с методом doCoding(), его имплементации:
    Drummer, guitarist, trombonist.
    6) Интерфейс Fighter с методом doFight(), его имплементации:
    StreetFighter, Boxer, Judoka.
    7) Интерфейс Politician с методом doPolitic(), его имплементации:
    Trump,Biden, Merkel.
    8) Интерфейс SortingAlgorithm с методом doSort(), его имплементации:
    MergeSort, InsertionSort, QuickSort.
    9) Интерфейс Printer с методом doPrint(), его имплементации:
    ConsolePrinter, FilePrinter.
    10) Интерфейс Programmer с методом doCoding(), его имплементации:
    Junior, Middle, Senior.

    11) Интерфейс Programmer с методом doCoding(), его имплементации:
    Junior, Middle, Senior.
    12) Интерфейс Programmer с методом doCoding(), его имплементации:
    Junior, Middle, Senior.
    13) Интерфейс Programmer с методом doCoding(), его имплементации:
    Junior, Middle, Senior.
    14) Интерфейс Programmer с методом doCoding(), его имплементации:
    Junior, Middle, Senior.
    15) Интерфейс Programmer с методом doCoding(), его имплементации:
    Junior, Middle, Senior.

    11. ПРАКТИЧЕСКАЯ РАБОТА № 11
    Цель работы
    Разобраться с использованием Spring boot.
    11.1. Теоретическая часть
    У нас есть прекрасные системы сборки приложений, но все равно возникают проблемы с версиями зависимостей. Нужно постоянно следить за версиями, часто возникают проблемы с тем, что одна библиотека зависит от другой с устаревшей версией, а вы используете более новую. Также очень неудобно в Spring постоянно писать один и тот же код, чтобы просто запустить программу с контекстом. Хотелось бы все это автоматизировать. И хотелось бы сделать такие библиотеки, чтобы можно было добавить зависимость на одну интеграцию от Spring, и сразу же можно было ее использовать, так еще и чтобы была конфигурация по умолчанию. И хочется еще, чтобы по одному файлу с настройками поднимались все нужные бины, и можно было сразу писать бизнес-логику. И самое удивительное – такая технология есть. Это Spring Boot. Она позволяет просто скачать проект, добавить нужные зависимости, и сразу писать код для бизнес-логики.
    11.2. Задание
    Создать приложение с использованием Spring Boot Starter Initializr
    (https://start.spring.io/) с такими зависимостями:
    – Spring Web;
    – Lombok;
    – Validation;
    – Spring boot Actuator.
    Запустить приложение и удостовериться, что не появилось никаких ошибок. Добавить все эндпоинты в Actuator, сделать HTTP-запрос на проверку состояния приложения. Собрать jar-файл приложения, запустить и проверить состояние при помощи REST-запроса.

    12. ПРАКТИЧЕСКАЯ РАБОТА № 12
    Цель работы
    Работа с жизненным циклом компонентов. Аннотации PostConstruct,
    PreDestroy.
    12.1. Теоретическая часть
    Для использования аннотаций PostConstruct, PreDestroy требуется
    Spring boot. Для того, чтобы создать консольное приложение в Spring boot, воспользуйтесь CommandLineRunner.
    Контекст также контролирует жизненный цикл бина (рисунок 33).
    Рисунок 33 – Жизненный цикл бина
    Иногда может понадобиться произвести какие-то действия не в конструкторе, так как при вызове конструктора могут не быть инициализированы все бины (в случае если у нас есть field injection или setter injection), а когда бин уже полностью подготовлен. Для этого и используется аннотация PostConstruct.
    Для логики при уничтожении бина используется аннотация PreDestroy.
    Пример кода с аннотациями:
    @Component public class PostConstructSample {
    @PostConstruct public void init() {
    System.out.println("Bean is ready");
    }
    }

    12.2. Задание
    Создать приложение, которое при запуске берет данные из одного файла, хеширует, а при остановке приложения удаляет исходный файл, оставляя только файл с захешированными данными. Названия первого и второго файла передаются в качестве аргументов при запуске. При отсутствии первого файла создает второй файл и записывает в него строку null.
    Реализовать с использованием аннотаций PostConstruct, PreDestroy.

    13. ПРАКТИЧЕСКАЯ РАБОТА № 13
    Цель работы
    Конфигурирование приложения. Environment.
    13.1. Теоретическая часть
    У приложения может быть достаточно много настроек. Самым банальным примером является строка подключения к базе данных. Не хочется каждый раз лезть в код, когда запускаешь приложение в другой среде – локальной, тестовой, продакшн. И Spring предоставляет невероятно удобный способ конфигурирования приложений. Вся конфигурация находится в одном файле в папке resources – по умолчанию это application.properties, но часто используется application.yml, так как yml формат более читаем. В нем мы можем определять какие-то свойства, которые можем получить в дальнейшем в приложении. Например, добавим в application.yml имя пользователя: program: user: name: User
    А теперь попробуем получить эту проперти в классе User
    @Component public class User {
    @Value("${program.user.name}") private String name;
    @PostConstruct public void init() {
    System.out.println(name);
    }
    }
    Запускаем программу, и видим, что наше значение из файла вывелось.

    13.2. Задание
    Создать файл application.yml в папке resources, добавить в него такие свойства:
    – student.name – имя студента;
    – student.last_name – фамилия студента;
    – student.group – название группы студента.
    При запуске приложения выведите данные свойства в консоль при помощи интерфейса Environment или аннотации Value.

    14. ПРАКТИЧЕСКАЯ РАБОТА № 14
    Цель работы
    Знакомство со Spring MVC. Работа с Rest API в Spring.
    14.1. Теоретическая часть
    Как мы знаем, основная задача сервера – принимать запросы, обрабатывать их и возвращать некий ответ. Чаще всего для этого используется протокол HTTP. Но протокол HTTP не описывает принципов по построению запроса, он является лишь стандартом взаимодействия. Требуется какой-то принцип, удобный, понятный и который легко можно отлаживать. Для этого существует REST API, с которым я советую ознакомиться самостоятельно, ибо информации о нем чрезвычайно много. Я лишь акцентирую внимание контроллеры, созданные для работы с REST API, а также Spring MVC (Model-
    View-Controller).
    Входной точкой для любого запроса является контроллер – класс, аннотированный аннотацией Controller или RestController. Метод, помеченный аннотацией RequestMapping, GetMapping, PostMapping,
    PutMapping является одной из входных точек для HTTP запроса. Попробуем сделать простой контроллер, который будет возвращать строку.
    @Controller public class SimpleController {
    @GetMapping("/hello") public @ResponseBody String hello() { return "Hello";
    }
    }
    Аннотация ResponseBody значит, что то, что вернет метод, будет преобразовано в тело ответа. Главное отличие RestController от Controller в том, что RestController является по сути объединением двух аннотаций –
    Controller и ResponseBody. Просто, но эффектно и удобно. Тогда возникает вопрос – зачем нужна просто аннотация Controller? Мы же почти всегда хотим
    какой-то ответ на запрос. Но в некоторых случаях нам нужно вернуть страницу – статический html или же сгенерированный шаблонизатором. Для этого можно использовать просто контроллер, возвращающий строку. Spring попытается найти какой-то документ по названию, совпадающему со строкой, которую вы вернули. По поводу того, что может возвращать метод контроллера, лучше почитать в документации
    Spring
    (https://docs.spring.io/spring-framework/docs/current/reference/html/web.html).
    Допустим, нам нужно получить тело запроса в формате json, и преобразовать в объект, а затем где-то использовать. Эта проблема решается одной аннотацией и одной настройкой.
    @Controller public class SimpleController {
    @GetMapping(value = "/hello", consumes =
    MediaType.APPLICATION_JSON_VALUE) public @ResponseBody String hello(@RequestBody User user) { return "Hello";
    }
    } consumes определяет, какой вид в теле запроса потребляет метод.
    GetMapping означает, что он принимает GET запрос.
    Контроллеры в Spring – чрезвычайно обширная тема, но очень полезная, они сильно упрощают разработку.
    1   2   3   4   5


    написать администратору сайта