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

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

  • 19.2. Задание Создать файл logback.xml, добавить логирование во все методы классов- сервисов. 20. ПРАКТИЧЕСКАЯ РАБОТА № 20 Цель работы

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

  • 21. ПРАКТИЧЕСКАЯ РАБОТА № 21 Цель работы Проксирование. Аннотация Transactional. Аннотация Async. 21.1. Теоретическая часть

  • 22. ПРАКТИЧЕСКАЯ РАБОТА № 22 Цель работы Планирование заданий. Scheduler в Spring. 22.1. Теоретическая часть

  • 23. ПРАКТИЧЕСКАЯ РАБОТА № 23 Цель работы Использование Spring Security для аутентификации и авторизации пользователей. 23.1. Теоретическая часть

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

  • 24.2. Задание Написать модульное тестирование для всех классов сервисов приложения из предыдущего задания. 25. ОПИСАНИЕ ВЫПОЛНЕНИЯ РАБОТ

  • 25.2. Порядок выполнения индивидуального задания

  • 26. ЗАЩИТА ПРАКТИЧЕСКИХ РАБОТ 26.1. Результат практической работы

  • 26.2. Этапы защиты практической работы

  • БИБЛИОГРАФИЧЕСКИЙ СПИСОК

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


    Скачать 1.94 Mb.
    НазваниеПрактикум для студентов, обучающихся по направлению подготовки 09. 03. 04 Программная инженерия
    АнкорМетодичка java
    Дата18.05.2023
    Размер1.94 Mb.
    Формат файлаpdf
    Имя файлаМетодичка По Шаблонам Java.pdf
    ТипПрактикум
    #1142180
    страница5 из 5
    1   2   3   4   5
    18.2. Задание
    Переписать код предыдущего задания с использованием сервисов и отделения логики контроллера от логики сервиса и репозитория. В программе всё взаимодействие с базой данных должно быть реализовано через репозитории Spring Data Jpa.

    19. ПРАКТИЧЕСКАЯ РАБОТА № 19
    Цель работы
    Знакомство с логированием с использованием Logback в Spring.
    19.1. Теоретическая часть
    Логирование – очень важная часть разработки. Часто мы не имеем возможности запустить дебаггер, воспроизвести нужную проблему и посмотреть, что происходит в программе в ней. Тем более, когда проблема не воспроизводится, без логирования мы вообще фактически остаемся ни с чем.
    Воспользуемся библиотекой Logback для реализации логирования, а также Slf4j вместе с аннотациями Lombok для уменьшения boilerplate. После добавления всех нужных зависимостей (spring boot starter logging), создадим файл logback.xml, и сделаем логирование всей информации в стандартный поток вывода, а также в файл, который при превышении порога или прохождении 30 дней создает новый файл логов, а старый сжимает при помощи gzip. Но перед заполнением logback.xml, рассмотрим уровни логирования:
    – Error – выводятся ошибки, то, что может критически повлиять на работу системы;
    – Warn – предупреждения, которые не сломают логику, но могут негативно повлиять;
    – Info – стандартный вывод информации;
    – Debug – информация для дебага;
    – Trace – максимально полная информация, очень редко используется, лучше не делайте логирование в файл с уровнем trace, иначе впоследствии логи будут практически нечитаемы.
    А теперь заполним logback.xml:

    >


    %d{HH:mm:ss.SSS} [%thread] %-5level
    %logger{36} – %msg%n


    >
    application.log
    >
    application.%d{yyyy-MM- dd}.gz
    30
    3GB


    %-4relative [%thread] %-5level %logger{35}
    – %msg%n







    Корневой элемент – configuration. В Logback есть 3 основных элемента:
    – Logger – контекст для логирования сообщений, может иметь несколько аппендеров;
    – Appender – место, куда кладутся логи, например, файлы;
    – Layout – то, как должны выглядеть логи.
    В данном случае мы создаем 2 аппендера: в стандартный поток вывода, а также в файл с созданием файла каждый день, максимальное количество 30, а также максимальный размер 3 ГБайт. В pattern описывается паттерн, как должен выглядеть лог. Это и есть тот самый Layout.
    rollingPolicy как раз-таки определяет обновление файла логов, чтобы он не разрастался, и определяет максимальное количество файлов, максимальный размер файлов.
    TimeBasedRollingPolicy обозначает, что изменение основывается на времени.
    Теперь можно запустить приложение и посмотреть, создался ли файл, записываются ли логи. Если все нормально, остается добавить собственное логирование. Для этого воспользуемся аннотацией Slf4j, и залогируем какой- либо сервис:
    @Service
    @RequiredArgsConstructor
    @Slf4j public class UserServiceImpl implements UserService { private final UserRepository userRepository; public List getUsers() { log.info("Find all users"); return userRepository.findAll();
    } public void saveOrUpdate(User user){ log.info("Save user {}", user); userRepository.save(user);
    }
    }
    Теперь можно запустить и проверить, все ли залогировалось, а также открыть файл и проверить, записались ли туда логи.
    Логирование не является сложным, но имеет огромное значение при отладке программ.
    19.2. Задание
    Создать файл logback.xml, добавить логирование во все методы классов- сервисов.

    20. ПРАКТИЧЕСКАЯ РАБОТА № 20
    Цель работы
    Использование Spring
    AOP
    . Pointcut, JoinPoint. Advice.
    20.1. Теоретическая часть
    Нам может потребоваться часто создать такую логику, которая будет присутствовать сразу во множестве разнообразных методов – например, обернуть все методы взаимодействия к БД в транзакцию, или логировать входные параметры всех методов сервисов. Для реализации такой логики идеально подойдет Aspect Oriented Programming (AOP) – парадигма программирования для реализации сквозной логики. Мы можем одну и ту же логику применять сразу к множеству модулей в программе (рисунок 35).
    Рисунок 35 – Представление Aspect Oriented Programming (AOP)
    В аспектно-ориентированном программировании существует несколько основных понятий:
    – Aspect – класс, реализующий сквозную функциональность;

    – Advice – блок кода, который должен выполниться в каких-то определенных местах работы программы;
    – Pointcut – некий предикат, который описывает ту точку кода, в которой выполняется Advice;
    – JoinPoint – конкретная точка выполнения программы, в которой будет исполняться Advice. То есть, Pointcut это множество JoinPoint точек.
    А теперь попробуем сделать простой аспект, который будет логировать просто входные параметры всех классов сервисов. Не забудьте добавить аннотацию EnableAspectJAutoProxy над конфигурацией.
    @Slf4j
    @Component
    @org.aspectj.lang.annotation.Aspect public class Aspect {
    @Before("allServiceMethods()") public void logParameters(JoinPoint joinPoint) { log.info("Parameters: {}", joinPoint.getArgs());
    }
    @Pointcut("within(ru.mirea.springcourse.service.*)") public void allServiceMethods() {}
    }
    Аннотация Aspect создает специальный аспект, в котором будут описываться Pointcut, Advice.
    Before – аннотация, которая обозначает Advice, который будет выполняться перед выполнением некоего метода.
    Есть различные аннотации, например, After, AfterThrowing, Around,
    AfterReturning.
    Pointcut описывает набор точек выполнения программы – методов, в которых выполняется Advice:
    – within – объекты заданного типа или классов пакета или подпакетов;
    – execution – по имени метода;
    – this – прокси реализует заданный тип;
    – bean – имеет определённый идентификатор или имя;

    – annotation – помечены указанной аннотацией.
    Теперь можно запустить приложение, и проверить работоспособность аспектов.
    20.2. Задание
    Для приложения из предыдущего задания добавить логирование времени выполнения каждого метода сервиса с использованием Spring AOP.

    21. ПРАКТИЧЕСКАЯ РАБОТА № 21
    Цель работы
    Проксирование. Аннотация Transactional. Аннотация Async.
    21.1. Теоретическая часть
    В данной работе мы изучим проксирование, на котором основаны многие функциональные возможности в Spring, например, AOP, планирование заданий, асинхронность.
    Логично, что проксирование основано на паттерне Прокси. Создается объект, который подменяет исходный, с дополнительной логикой. При этом проксирование может быть многоуровневое, прокси может проксировать другой прокси, так как он просто внутри использует предыдущий объект.
    Есть различные имплементации проксирования: JDK-проксирование,
    CGLIB. Также существует AspectJ-проксирование на этапе компиляции, но мы его не будем сейчас затрагивать. JDK имплементация основана на том, что создается объект, который имплементирует все интерфейсы класса, который имплементирует целевой объект. При таком типе проксирования можно использовать только public методы.
    CGLIB имплементация основана на том, что прокси наследуется от целевого класса, и таким образом может использовать методы. В таком случае можно проксировать все методы, кроме private.
    Изначально Spring пытается воспользоваться проксированием на основе интерфейсов, если не получается, то использует CGLIB. Но с версии Spring boot 2 по умолчанию используется CGLIB, что имеет большое значение, так как если мы будем использовать Spring с Kotlin, то нужно не забывать о специальном extension, который все классы делает open, иначе Spring просто не сможет проксировать.
    Аннотация Transactional позволяет оборачивать метод в транзакцию, не прописывая дополнительный код. Если на простом уровне, то он просто оборачивает метод в такой код:
    var transaction = session.beginTransaction(); try { invokeMethod(); transaction.commit();
    } catch(Exception e){ transaction.rollback();
    }
    Эта аннотация уменьшает код, при этом передавая всю работу с транзакциями на Spring. Также у аннотации есть параметр readonly, который стоит ставить в true, если не производится никаких изменений в БД, а только чтение. Это убирает различные дополнительные проверки, улучшает производительность метода.
    Аннотация Async делает метод асинхронным. Он исполняет метод в отдельном треде.
    21.2. Задание
    Для приложения из предыдущего задания пометить все классы сервисов, в которых происходит взаимодействие с базой данных, как
    Transactional. Добавить отправку информации о сохранении каждого объекта по электронной почте, создав отдельный класс EmailService с асинхронными методами отправки сообщений. Для асинхронности методов используйте аннотацию Async.

    22. ПРАКТИЧЕСКАЯ РАБОТА № 22
    Цель работы
    Планирование заданий. Scheduler в Spring.
    22.1. Теоретическая часть
    Иногда требуется выполнять какие-то запланированные задания, которые выполняются в определенный момент времени – например, очистку таблицы от устаревших значений, подгрузка новых значений, инвалидация кэша. Для этого используется Scheduler. Не забудьте добавить аннотацию
    EnableScheduling над конфигурацией.
    Теперь создадим класс
    SchedulerService:
    @Service public class SchedulerServiceImpl implements
    SchedulerService {
    @Scheduled(cron = "0 * * * * *")
    @Override public void doScheduledTask() {
    System.out.println("Scheduled task");
    }
    }
    Для того, чтобы создать запланированное задание, нужна аннотация
    Scheduled. Данный метод затем проксируется и запускается по расписанию. cron означает cron-значение, описывающее время запуска. В данном случае оно будет выполняться каждую минуту.
    22.2. Задание
    Для приложения из предыдущего задания создать класс-сервис с методом, который будет вызываться каждые 30 минут и очищать определённую директорию, а затем создавать по файлу для каждой из сущностей и загружать туда все данные из базы данных. Также добавить возможность вызывать данный метод с использованием Java Management
    Extensions (JMX).

    23. ПРАКТИЧЕСКАЯ РАБОТА № 23
    Цель работы
    Использование Spring Security для аутентификации и авторизации пользователей.
    23.1. Теоретическая часть
    Каждое приложение должно так или иначе поддерживать защиту от несанкционированного доступа. Для этого предоставлена прекрасная технология Spring Security.
    Самым основным элементом Security является Filter Chain – цепочка фильтров. Вся безопасность реализуется через данную цепочку фильтров. По очереди каждый фильтр проверяет запрос, получает нужные данные, в случае чего блокирует дальнейшую фильтрацию. Также вместо отдельного фильтра может быть FilterChainProxy, который хранит в себе семейство иных фильтров.
    Также в фильтре можно создать имплементацию интерфейса
    Authentication, которую можно положить в SecurityContextHolder. Дело в том, что для каждого треда хранится отдельный экземпляр SecurityContextHolder, в котором хранится аутентификация для пользователя. Благодаря этому мы, например, можем получить Principal в контроллере.
    Но это не все – есть огромное количество самых разнообразных абстракций в Spring security, однако на данный момент мы затронем самые базовые конфигурации для Security.
    @Configuration public class SecurityConfig extends
    WebSecurityConfigurerAdapter {
    @Override protected void configure(HttpSecurity http) throws
    Exception {
    }
    }

    Класс, наследующийся от WebSecurityConfigurerAdapter, является фактически входной точкой со всей конфигурацией. Для начала запретим все эндпоинты, кроме /login, /logout для неавторизованных пользователей, а также отключим Cross Origin Resource Sharing (CORS) и Cross Site Request Forgery
    (CSRF). Они сейчас не имеют значение, но могут усложнить изучение Spring
    Security:
    @Configuration public class SecurityConfig extends
    WebSecurityConfigurerAdapter {
    @Override protected void configure(HttpSecurity http) throws
    Exception { http.csrf().disable().cors().disable()
    .authorizeRequests().antMatchers("/login",
    "/logout").permitAll()
    .anyRequest().authenticated();
    }
    }
    Теперь хотелось бы добавить форму логина, а также какой-то источник логинов и паролей пользователей:
    @Configuration public class SecurityConfig extends
    WebSecurityConfigurerAdapter {
    @Override protected void configure(HttpSecurity http) throws
    Exception { http.csrf().disable().cors().disable()
    .authorizeRequests().antMatchers("/login",
    "/logout").permitAll()
    .anyRequest().authenticated()
    .and().formLogin()
    .and().userDetailsService(userDetailsService());
    }
    public UserDetailsService userDetailsService() {
    InMemoryUserDetailsManager userDetailsService = new
    InMemoryUserDetailsManager(); userDetailsService.createUser(new
    User("user",
    "password", List.of(new SimpleGrantedAuthority("ROLE_USER")))); return userDetailsService;
    }
    @Bean
    PasswordEncoder encoder() { return NoOpPasswordEncoder.getInstance();
    }
    }
    PasswordEncoder – класс, который отвечает за кодирование паролей. В данном случае используется NoOpPasswordEncoder, но никогда его не стоит использовать в реальном проекте – он никак не шифрует пароли. В данном случае он используется просто для простоты. А теперь запустим проект и попробуем перейти на защищенный эндпоинт. Нас отправит на /login
    (рисунок 36).
    Рисунок 36 – Форма авторизации
    Попробуем ввести наш логин «user» и пароль «password». После логина перейдем на защищенный эндпоинт, и увидим информацию.

    Также нам хотелось бы еще где-то хранить сессию. Для этого используется Spring Session, который активируется добавлением одной зависимости – spring session jdbc.
    23.2. Задание
    В приложении из предыдущего задания добавить возможность регистрации и авторизации пользователей, хранение cookie сессий в базе данных PostgreSQL, хеширование паролей алгоритмом Bcrypt, защиту всех запросов, кроме запросов на авторизацию и регистрацию, от неавторизированных пользователей.

    24. ПРАКТИЧЕСКАЯ РАБОТА № 24
    Цель работы
    Тестирование в Spring Framework с использованием Junit.
    24.1. Теоретическая часть
    В данном задании мы обратим внимание на модульное тестирование – такой вид тестирования, в котором тестируется отдельный модуль, класс, в изоляции от остальных, на правильное функционирование. Модульное тестирование важно не на стадии создания данных тестов, а при дальнейшем развитии кодовой базы, когда тесты не дадут сломаться тому, что уже работает. Для написания модульных тестов будем использовать библиотеку
    JUnit, которая тоже прекрасно интегрирована с Spring.
    Также нам потребуется создание mock объектов – реализаций некоторых объектов-пустышек, не выполняющих логики, либо симулирующие выполнение какой-то логики. Также мы можем определять, что они будут возвращать, для удобства тестирования. Мы будем тестировать
    UserService из предыдущего задания.
    Для начала создадим класс в папке test UserServiceImplTest, и добавим два метода – getUsers, saveOrUpdate, и пометим аннотацией Test. class UserServiceImplTest {
    @Test void getUsers() {
    }
    @Test void saveOrUpdate() {
    }
    }
    Уже сейчас мы можем запустить, и тесты успешно пройдут. Но нам нужно все же проверить какую-то логику. Но для начала нам нужно сделать mock объект интерфейса UserRepository. Для этого добавим аннотацию

    ExtendWith для активации Mockito, а также добавим свойство UserRepository с аннотацией Mock:
    @ExtendWith(MockitoExtension.class) class UserServiceImplTest {
    @Mock private UserRepository userRepository;
    @Test void getUsers() {
    }
    @Test void saveOrUpdate() {
    }
    }
    Теперь уже добавим логику в тест getUsers:
    @ExtendWith(MockitoExtension.class) class UserServiceImplTest {
    @Mock private UserRepository userRepository;
    @Test void getUsers() {
    User user = new User(); user.setFirstName("Vasya");
    User user2 = new User(); user2.setFirstName("Dima");
    Mockito.when(userRepository.findAll()).thenReturn(List.of(user, user2));
    UserService userService = new
    UserServiceImpl(userRepository);
    Assertions.assertEquals(2, userService.getUsers().size());
    Assertions.assertEquals("Vasya", userService.getUsers().get(0).getFirstName());
    }
    @Test void saveOrUpdate() {

    }
    }
    Assertions отвечает за проверку данных – являются ли они теми, которые мы ожидаем от программы, или нет. Теперь добавим логику для метода saveOrUpdate:
    @ExtendWith(MockitoExtension.class) class UserServiceImplTest {
    @Mock private UserRepository userRepository;
    @Captor
    ArgumentCaptor captor;
    @Test void getUsers() {
    User user = new User(); user.setFirstName("Vasya");
    User user2 = new User(); user2.setFirstName("Dima");
    Mockito.when(userRepository.findAll()).thenReturn(List.of(user, user2));
    UserService userService = new
    UserServiceImpl(userRepository);
    Assertions.assertEquals(2, userService.getUsers().size());
    Assertions.assertEquals("Vasya", userService.getUsers().get(0).getFirstName());
    }
    @Test void saveOrUpdate() {
    User user = new User(); user.setFirstName("Vitya");
    UserService userService = new
    UserServiceImpl(userRepository); userService.saveOrUpdate(user);
    Mockito.verify(userRepository).save(captor.capture());
    User captured = captor.getValue();
    assertEquals("Vitya", captured.getFirstName());
    }
    }
    ArgumentCaptror отвечает за перехват аргументов. Нам нужно узнать, поменялся ли как-то объект User в процессе выполнения метода UserService, поэтому нам нужно перехватить аргумент и проверить его.
    Тестирование также важно, как и сама разработка, ведь любой код в первую очередь пишется для того, чтобы его кто-то использовал – как приложение, как библиотеку, не важно. Код всегда должен выполнять бизнес- требования, иначе и само программирование становится бесполезным.
    24.2. Задание
    Написать модульное тестирование для всех классов сервисов приложения из предыдущего задания.

    25. ОПИСАНИЕ ВЫПОЛНЕНИЯ РАБОТ
    25.1. Последовательность выполнения практической работы
    Для выполнения практических работ необходимо:
    1) на рабочем месте, где будут выполняться практические работы, установить следующие средства разработки: а) OpenJDK версии 11 и выше; б) InteliJ IDEA Community Edition (желательно Ultimate Edition, можно получить по студенческой лицензии на сайте Jetbrains); в) Docker;
    2) создать пустой проект в InteliJ IDEA;
    3) создать пустой класс, содержащий статический main метод;
    4) запустить созданную программу и убедиться в работоспособности.
    25.2. Порядок выполнения индивидуального задания
    Индивидуальное задание должно быть оформлено в отдельном проекте.
    Для проверки работоспособности выполненного индивидуального задания следует использовать отдельный класс с методом main.

    26. ЗАЩИТА ПРАКТИЧЕСКИХ РАБОТ
    26.1. Результат практической работы
    Результатом практической работы является:
    1) рабочий проект, выполненный в соответствии с заданием практической работы;
    2) отчет, содержащий все этапы выполненной работы, оформленный по примеру.
    26.2. Этапы защиты практической работы
    Этапы защиты практической работы:
    1) демонстрация рабочего проекта, выполненного в соответствии с заданием;
    2) ответы на дополнительные вопросы по рабочему проекту (студент должен владеть теоретической базой, свободно читать и комментировать строки листинга программы, уметь формулировать выводы о проделанной работе);
    3) отчет по практической работе предоставляется в электронном виде.

    ПЕРЕЧЕНЬ СОКРАЩЕНИЙ
    AOP
    – Aspect Oriented Programming

    API

    Application programming Interface

    CORS –
    Cross Origin Resource Sharing

    CSRF –
    Cross Site Request Forgery

    DI

    Dependency Injection

    DSL

    Domain specific language

    DTO

    Data Transfer Object

    HQL

    Hibernate Query Language

    HTTP –
    HyperText Transfer Protocol

    IoC

    Inversion of Control

    JDK

    Java Development Kit

    JMX

    Java Management Extensions

    JPA

    Java Persistence API

    JVM

    Java Virtual Machine

    MVC –
    Model-View-Controller

    ORM –
    Object Relational Mapping

    SQL

    Structured query language

    xml

    eXtensible Markup Language

    БД

    база данных


    БИБЛИОГРАФИЧЕСКИЙ СПИСОК
    1. Стелтинг С., Маасен О. Применение шаблонов Java. Библиотека профессионала.: Пер. с англ. — М.: Издательский дом "Вильяме", 2002. —
    576 с.: ил. — Парал. тит. англ.
    2. Functional Interfaces in Java: Fundamentals and Examples 1st ed. Edition,
    Kindle
    Edition
    [Электронный ресурс].
    URL: https://www.amazon.com/Functional-Interfaces-Java-Fundamentals-Examples- ebook/dp/B07NRHQSCW (дата обращения: 29.01.21). Заголовок с экрана.
    3. Hibernate Search 6.0.0.Final: Reference Documentation [Электронный ресурс].
    URL: https://docs.jboss.org/hibernate/stable/search/reference/en-
    US/html_single/ (дата обращения: 29.01.21). Заголовок с экрана.
    4. Паттерны проектирования на Java. Каталог Java-примеров.
    [Электронный ресурс]. URL: https://refactoring.guru/ru/design-patterns/java
    (дата обращения: 29.01.21). Заголовок с экрана.
    5. Руководство по
    Spring
    [Электронный ресурс].
    URL: https://proselyte.net/tutorials/spring-tutorial-full-version/
    (дата обращения:
    29.01.21). Заголовок с экрана.
    6. The
    Reactive
    Manifesto
    [Электронный ресурс].
    URL:
    https://www.reactivemanifesto.org/ (дата обращения: 29.01.21). Заголовок с экрана.
    7. Spring Framework Documentation [Электронный ресурс]. URL: https://docs.spring.io/spring-framework/docs/current/reference/html/web.html
    (дата обращения: 29.01.21). Заголовок с экрана.
    8. Hibernate Search 6.0.0. Final: Reference Documentation [Электронный ресурс].
    URL: https://docs.jboss.org/hibernate/stable/search/reference/en-
    US/html_single/ (дата обращения: 29.01.21). Заголовок с экрана.
    1   2   3   4   5


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