├── .gitignore ├── README.md ├── ReleaseNotes.md ├── cv.md ├── description.md ├── doc ├── lesson07.md ├── video1.md ├── video2.1.md ├── video2.2.md ├── video2.3.md ├── video2.4.md ├── video3.md ├── video4.md └── video5-vcs-git.md ├── graduation.md ├── pom.xml └── src └── main └── java └── ru └── javawebinar └── topjava └── Main.java /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | out 3 | target 4 | *.iml 5 | log 6 | *.patch 7 | 8 | 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [Java Enterprise Online Project](https://javaops.ru/view/topjava) 2 | =============================== 3 | Разработка полнофункционального Spring/JPA Enterprise приложения c авторизацией и правами доступа на основе ролей с использованием наиболее популярных инструментов и технологий Java: Maven, Spring MVC, Security, JPA(Hibernate), REST(Jackson), Bootstrap (css,js), DataTables, jQuery + plugins, Java 8 Stream and Time API и хранением в базах данных Postgresql и HSQLDB. 4 | 5 | ![topjava_structure](https://javaops.ru/static/images/projects/top-scheme.jpg) 6 | 7 | Когда вы слышите что-то, вы забываете это. 8 | Когда вы видите что-то, вы запоминаете это. 9 | Но только когда вы начинаете делать это, 10 | вы начинаете понимать это 11 | 12 | Старинная китайская поговорка 13 | 14 | ## Описание и план проекта 15 | ### Демо разрабатываемого приложения 16 | ### [Изменения проекта (Release Notes)](ReleaseNotes.md) 17 | ### Требования к участникам, Wiki 18 | ### Составление резюме, подготовка к интервью, поиск работы 19 | 20 | Обновленное вводное занятие (обязательно смотреть все видео) 21 | =============== 22 | ## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 1. [Вступление, история, команда, источники](doc/video1.md) 23 | 24 | ## Обзор наиболее востребованных технологий, которые будут изучаться на курсе TopJava 25 | ## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 2.1. [Часть 1: инфраструктура](doc/video2.1.md) 26 | 27 | ## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 2.2. [Часть 2: frameworks Spring, ORM](doc/video2.2.md) 28 | 29 | ## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 2.3. [Часть 3: тренды](doc/video2.3.md) 30 | 31 | ## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 2.3. [Часть 4: обзор разрабатываемого приложения](doc/video2.4.md) 32 | 33 | ## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 3. [Рекомендуемые подходы к обучению на курсе](doc/video3.md) 34 | 35 | ## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 4. [Структура приложения (многоуровневая архитектура)](doc/video4.md) 36 | ### [Демо приложения](http://javaops-demo.ru/topjava) 37 | 38 | ## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 5. [Системы управления версиями. Git](doc/video5-vcs-git.md) 39 | 40 | ## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 6. Работа с проектом (выполнять инструкции) 41 | - **ВНИМАНИЕ: выбирайте для проекта простой пусть без пробелов и русских букв, например, `c:\projects\topjava\` (Windows). Иначе впоследствии будут проблемы** 42 | - **Плагин Git Intergation уже не требуется, а вкладку `Version control` в IDEA переименовали в `Git`** 43 | - **C Ultimate IDEA сейчас сложности**, надеемся что временные. 44 | - Скачать IDEA и установливать плагины [можно по инструкции](https://github.com/JavaOPs/topjava/wiki/IDEA#download) 45 | - После Trial 30 дней [способы продлить использование](https://github.com/JavaOPs/topjava/wiki/IDEA#licence) 46 | 47 | Для переключения режима отображения изменений из вкладки `Commit` в `Git: Local Changes` нужно переключить `Settings/Preferences | Version Control | Commit | Use non-modal commit interface` или в контекстном меню вкладки `Commit`: 48 | 49 | ![image](https://user-images.githubusercontent.com/13649199/105491518-72d8f300-5cc7-11eb-8b79-c46382562deb.png) ![image](https://user-images.githubusercontent.com/13649199/105488663-05c35e80-5cc3-11eb-962e-30f403d623e8.png) 50 | 51 | ### Патч [prepare_to_HW0.patch](https://drive.google.com/file/d/1LNPpu9OkuCpfpD8ZJHO-o0vwu49p2i5M) (скачать и положить в каталог вашего проекта) 52 | 53 | > Проект постоянно улучшается, поэтому видео иногда отличается от кода проекта. Изменения указываю после видео: 54 | > - переименовал класс `UserMealWithExceed` и его поле `exceed` в `UserMealWithExcess.excess` 55 | > - в `UserMeals/UserMealWithExcess` поля изменились на `private` 56 | > - обновил данные `UserMealsUtil.meals` и переименовал некоторые переменные, поля и методы 57 | > - добавил `UserMealWithExcess.toString()` и метод для выполнения _Optional домашнего задания_ 58 | > - метод фильтрации в `TimeUtil` переименовал в `isBetweenHalfOpen` (также изменилась логика сравнения: `startTime` включается в интервал, а `endTime` - не включается) 59 | 60 | ### GitHub поменял политику: теперь пушить нужно через токен. IDEA предложит его сгенерировать при пуше, или можно [создать токен в настройках](https://www.jetbrains.com/help/idea/github.html#register-account) 61 | - [Способы авторизации в GitHub](https://topjava.ru/blog/vvedeniye-v-git-github-ustanovka-i-nastroyka#6) 62 | 63 | ## Инструкция по шагам (из видео): 64 | - Установить ПО (Git, JDK8, IntelliJ IDEA, Maven) 65 | - Создать аккаунт на GitHub 66 | - Сделать Fork **ЭТОГО** проекта (https://github.com/JavaOPs/topjava) 67 | - Сделать локальный репозиторий проекта: 68 |
git clone https://github.com/[Ваш аккаунт]/topjava.git
69 | 70 | > Вместо Fork можно сделать [клонирование проекта](https://github.com/JavaOPs/topjava/wiki/Git#user-content-Клонирование-проекта): он не будет привязан к исходному https://github.com/JavaOPs/topjava и у него не будет истории. 71 | 72 | - Открыть и настроить проект в IDEA 73 | - Выставить кодировку UTF-8 в консоли 74 | - Поставить кодировку UTF-8 75 | - Опционально: поменять шрифт по умолчанию на DejaVu или на **новый [JetBrains Mono](https://habr.com/ru/company/jugru/news/t/484134/)** 76 | - По ходу видео сделать `Apply Patch...` скачанного патча `Prepare_to_HW0.patch` 77 | - Закоммитить и запушить изменения (`commit` + `push`) 78 | - Сделать ветку домашнего задания 79 | - Выполнить задание и залить на GitHub (`commit` + `push`) 80 | - Переключиться в основную ветку проекта `master`. 81 | 82 | ## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 7. [Maven](https://drive.google.com/file/d/1qEJTwv9FNUQjx-y9MSydH01xaAne0-hu) 83 | - [Как установить Maven 3 на Ubuntu или Windows](https://devcolibri.com/как-установить-maven-3-на-ubuntu-или-windows/) 84 | - [Руководство по Maven](https://topjava.ru/blog/apache-maven-osnovy-1) 85 | - Wiki: [Apache Maven](https://ru.wikipedia.org/wiki/Apache_Maven) 86 | - [The Central Repository](http://search.maven.org) 87 | - Дополнительно: 88 | - [Мой Wiki по Maven](https://github.com/JavaOPs/topjava/wiki/Maven) 89 | - [Основы Maven](https://www.youtube.com/watch?v=0uwMKktzixU) 90 | - JavaRush: [Основы Maven](https://javarush.ru/groups/posts/2523-chastjh-4osnovih-maven) 91 | - Инструмент сборки проектов [Maven](https://www.examclouds.com/ru/java/java-core-russian/lesson20) 92 | - [Maven Getting Started Guide](https://maven.apache.org/guides/getting-started/index.html) 93 | - [Видео: Maven vs Gradle vs SBT (Архипов, Борисов, Садогурский)](https://www.youtube.com/watch?v=21qdRgFsTy0) 94 | - [Build Lifecycle](http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html) 95 | - [Dependency Mechanism](http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html) 96 | 97 | ## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 8. [Как правильно относиться к техзаданию (ТЗ). Полуоткрытый интервал.](https://drive.google.com/file/d/1BpTzjNFjS0TSekCyt_xvt6YoLvuw5KTZ) 98 | - [Типы промежутков](https://ru.wikipedia.org/wiki/Промежуток_(математика)) 99 | 100 | ## ![hw](https://cloud.githubusercontent.com/assets/13649199/13672719/09593080-e6e7-11e5-81d1-5cb629c438ca.png) Домашнее задание HW0 101 | 102 | ### ВНИМАНИЕ: НЕ НАДО в репозиторий делать Pull Request со своими решениями! См. видео выше ("Работа с проектом") 103 | 104 | Реализовать метод `UserMealsUtil.filteredByCycles` через циклы (`forEach`): 105 | - должны возвращаться только записи между `startTime` и `endTime` 106 | - поле `UserMealWithExcess.excess` должно показывать, превышает ли сумма калорий за весь день значение `caloriesPerDay` 107 | 108 | Т. е. `UserMealWithExcess` - это запись одной еды, но поле `excess` будет одинаково для всех записей за этот день. 109 | 110 | > - Проверьте результат выполнения ДЗ (можно проверить логику в [http://javaops-demo.ru/topjava](http://javaops-demo.ru/topjava), список еды) 111 | > - Оцените Time complexity алгоритма. Если она больше O(N), например O(N*N) или N*log(N), сделайте O(N). 112 | > **Внимание: внимательно прочитайте про O(N). O - это любой коэффициент, 2*N это тоже O(N).** 113 | 114 | - Java 8 Date and Time API 115 | - Алгоритмы и структуры данных для начинающих: сложность алгоритмов 116 | - [Сложность алгоритмов и Big O Notation](https://threadreaderapp.com/thread/1470666237286010881) 117 | - [Головач: сложность алгоритмов в теме коллекций](https://www.youtube.com/watch?v=Ek9ijOiplNE&feature=youtu.be&t=778) 118 | - Time complexity 119 | - Временная сложность алгоритма 120 | - Вычислительная сложность 121 | 122 | #### ВНИМАНИЕ: варианты Optional делайте в одной ветке в разных методах `UserMealsUtil`. Проще делать, проще проверять 123 | 124 | ### Optional (Java 8 Stream API) 125 | ``` 126 | Реализовать метод `UserMealsUtil.filteredByStreams` через Java 8 Stream API. 127 | ``` 128 | - Видео: Доступно о Java 8 Lambda 129 | - Java 8: Lambda выражения 130 | - Java 8: Потоки 131 | - Pуководство по Java 8 Stream 132 | - [Полное руководство по Java 8 Stream API в картинках и примерах](https://annimon.com/article/2778) 133 | - [7 способов использовать groupingBy в Stream API](https://habrahabr.ru/post/348536) 134 | - Лямбда-выражения в Java 8 135 | - A Guide to Java 8 136 | - Шпаргалка Java Stream API 137 | - Алексей Владыкин: Элементы функционального программирования в Java 138 | - Yakov Fain о новом в Java 8 139 | - stream.map vs forEach` 147 | - без циклов по другим коллекциям/массивам (к ним также относим методы коллекций `addAll()/removeAll()`) 148 | - через Stream API за 1 проход по исходному списку `meals.stream()` 149 | - нельзя использовать внешние коллекции, не являющиеся частью коллектора 150 | - возможно дополнительные проходы по частям списка, при этом превышение должно считаться один раз для всего подсписка. Те например нельзя разбить список на на 2 подсписка с четными и нечетными датами и затем их объединить, с подсчетом превышения для каждого элемента. 151 | 152 | Временная сложность реализации должна быть O(N) (обратите внимание на п. 13 замечаний) 153 | Решение должно быть рабочим в общем случае (должно работать в приложении с многими пользователями, не только при запуске `main`) 154 | Нельзя 2 раза проходить по исходному списку (в том числе по его отфильтрованной или преобразованной копии) 155 | 156 | Ресурсы: 157 | - [Baeldung: Custom Collectors](https://www.baeldung.com/java-8-collectors#Custom) 158 | - [Руководство по Java 8 Stream API: Collector](https://annimon.com/article/2778#collector) 159 | - [Хватит писать циклы! Топ-10 лучших методов для работы с коллекциями из Java 8](https://javarush.ru/groups/posts/524-khvatit-pisatjh-ciklih-top-10-luchshikh-metodov-dlja-rabotih-s-kollekcijami-iz-java8) 160 | - [Понять Java Stream API](https://vc.ru/u/604567-yerlan-akzhanov/194409-ponyat-java-stream-api) 161 | 162 | ### Замечания по использованию Stream API: 163 | - Когда встречаешь что-то непривычное, приходится перестраивать мозги. Например, переход с процедурного на ООП-программирование дается непросто. Те, кто не знает шаблонов (и не хотят учить), также их встречают плохо. Хорошая новость в том, что если это принять и начать использовать, то начинаешь получать от этого удовольствие. И тут главное не впасть в другую крайность: 164 | - [Используйте Stream API проще (или не используйте вообще)](https://habrahabr.ru/post/337350/) 165 | - Если вас беспокоит производительность стримов, обязательно прочитайте про оптимизацию 166 | - ["Что? Где? Когда?"](http://optimization.guide/intro.html) 167 | - [Перформанс: что в имени тебе моём?](https://habrahabr.ru/company/jugru/blog/338732/) 168 | - [Performance это праздник](https://habrahabr.ru/post/326242/) 169 | 170 | При использовании Stream API производительность улучшится только на больших задачах, где возможно распараллеливание. 171 | Еще: просто так запустить и померить скорость JVM нельзя (как минимум надо дать прогреться и запустить очень большое число раз). Лучше использовать какие-нибудь бенчмарки, например [JMH](http://tutorials.jenkov.com/java-performance/jmh.html), который мы используем на другом проекте (Mastejava). 172 | 173 | ## ![error](https://cloud.githubusercontent.com/assets/13649199/13672935/ef09ec1e-e6e7-11e5-9f79-d1641c05cbe6.png) Замечания к HW0 174 | - 1: Код проекта менять можно! Одна из распространенных ошибок как в тестовых заданиях на собеседовании, так и при работе на проекте, что ничего нельзя менять. Конечно, при правках в рабочем проекте обязательно нужно проконсультироваться/проревьюироваться у авторов кода (находятся по истории VCS) 175 | - 2: Наследовать `UserMealWithExcess` от `UserMeal` нельзя, т. к. это разные сущности: Transfer Object и Entity. Мы будем их проходить на 2-м уроке. Это относится и к их зависимости друг от друга. 176 | - 3: Правильная реализация должна быть простой и красивой, можно сделать 2-мя способами: через стримы и через циклы. Сложность должна быть O(N), т. е. без вложенных стримов и циклов. 177 | - 4: При реализации через циклы посмотрите в `Map` на методы `getOrDefault` или `merge` 178 | - 5: **При реализации через `Stream` заменяйте `forEach` оператором `stream.map(..)`** 179 | - 6: Объявляйте переменные непосредственно перед использованием (если возможно - сразу с инициализацией). При объявлении коллекций в качестве типа переменной используйте интерфейс (Map, List, ..) 180 | - 7: Если IDEA предлагает оптимизацию (желтым подчеркивает), например, заменить лямбду на ссылку на метод (method reference), соглашайтесь (Alt+Enter) 181 | - 8: Пользуйтесь форматированием кода в IDEA: `Alt+Ctrl+L` 182 | - 9: Перед check-in (отправкой изменений на GitHub) просматривайте внесенные изменения (Git -> [Log](https://www.jetbrains.com/help/idea/log-tab.html) -> курсор на файл и Ctrl+D): не оставляйте в коде ничего лишнего (закомментированный код, TODO и пр.). Если файл не меняется (например только пробелы или переводы строк), не надо его чекинить, делайте ему `revert` (Git -> Revert / `Ctrl+Alt+Z`). 183 | - 10: `System.out.println` нельзя использовать нигде, кроме как в `main`. Позже введем логирование. 184 | - 11: Результаты, возвращаемые `UserMealsUtil.filteredByStreams`, мы будем использовать [в нашем приложении](http://javaops-demo.ru/topjava) для фильтрации по времени и отображения еды правильным цветом. 185 | - 12: Обращайте внимание на комментарии к вашим коммитам в Git. Они должны быть короткие и информативные (лучше на english) 186 | - 13: Не полагайтесь в решении на то, что список еды будет подаваться отсортированным. Такого условия нет. 187 | ----- 188 | 189 | > - ДЗ первого урока будет связано с созданием небольшого [CRUD](https://ru.wikipedia.org/wiki/CRUD)-приложения (в памяти, без базы данных) на JSP и сервлетах 190 | > - основы JavaScript необходимы для понимания проекта, начиная с 8-го занятия 191 | 192 | ### Полезные ресурсы 193 | #### HTML, JavaScript, CSS 194 | - [Basic HTML and HTML5](https://learn.freecodecamp.org/responsive-web-design/basic-html-and-html5/say-hello-to-html-elements/) 195 | - [Справочник по WEB](https://developer.mozilla.org/ru/) 196 | - [Видео по WEB-технологиям](https://www.youtube.com/user/WebMagistersRu/playlists) 197 | - [Изучение JavaScript в одном видеоуроке за час](https://www.youtube.com/watch?v=QBWWplFkdzw) 198 | - HTML, CSS, JAVASCRIPT, SQL, JQUERY, BOOTSTRAP 199 | - Введение в программирование на JavaScript 200 | - Стандарты кодирования для HTML, CSS и JavaScript’a 201 | - Основы работы с HTML/CSS/JavaScript 202 | - JavaScript - Основы 203 | - Основы JavaScript 204 | - Bootstrap 3 - Основы 205 | - jQuery для начинающих 206 | 207 | #### Java (базовые вещи) 208 | - [Сборник видео "Изучаем Java"](https://www.youtube.com/playlist?list=PLyxk-1FCKqockmP-fXZmHQ7UlYP3qvZRa) 209 | - 1-й урок MasterJava: Многопоточность 210 | - [Основы Java garbage collection](http://web.archive.org/web/20180831013112/https://ggenikus.github.io/blog/2014/05/04/gc) 211 | - Размер Java объектов 212 | - Введение в Java Reflection API 213 | - Структуры данных в картинках 214 | - Обзор java.util.concurrent.* 215 | - Синхронизация потоков 216 | - String literal pool 217 | - Маленькие хитрости Java 218 | - A Guide to Java 8 219 | 220 | ### Туториалы, разное 221 | - [Открытый курс: Spring Boot + HATEOAS](https://javaops.ru/view/bootjava) 222 | - [Что нужно знать о бэкенде новичку в веб-разработке](https://tproger.ru/translations/backend-web-development) 223 | - [Туториалы: Spring Framework, Hibernate, Java Core, JDBC](http://proselyte.net/tutorials/) 224 | 225 | #### Сервлеты 226 | - Как создать Servlet? Полное руководство. 227 | - [Сервлеты](https://metanit.com/java/javaee/4.1.php) 228 | 229 | #### Туториалы по Spring 230 | - [Юрий Ткач: Spring Framework - The Basics](https://www.youtube.com/playlist?list=PL6jg6AGdCNaWF-sUH2QDudBRXo54zuN1t) 231 | - [Java Brains: Spring Framework](https://www.youtube.com/playlist?list=PLC97BDEFDCDD169D7) 232 | - [Тимур Батыршинов: Spring Core - основы фреймворка, ядро](https://www.youtube.com/watch?v=CfHDr-19WWY&list=PL8X2nqRlWfaYYP1-qXjdPKE7bXYkl6aL4) 233 | - [alishev: Spring Framework](https://www.youtube.com/playlist?list=PLAma_mKffTOR5o0WNHnY0mTjKxnCgSXrZ) 234 | 235 | #### JDBC, SQL 236 | - Основы SQL на примере задачи 237 | - Уроки по JDBC 238 | - Learn SQL 239 | - Интуит. Основы SQL 240 | - Try SQL 241 | - Курс "Введение в базы данных" 242 | 243 | #### Разное 244 | - Вопросы по собеседованию, ресурсы для подготовки 245 | - Эффективная работа с кодом в IntelliJ IDEA 246 | - Quizful- тесты онлайн 247 | - Введение в Linux 248 | 249 | #### Книги 250 | - Джошуа Блох: Java. Эффективное программирование. Второе издание 251 | - Гамма, Хелм, Джонсон: Приемы объектно-ориентированного проектирования. Паттерны проектирования 252 | - Редмонд Э.: Семь баз данных за семь недель. Введение в современные базы данных и идеологию NoSQL 253 | - Brian Goetz: Java Concurrency in Practice 254 | - G.L. McDowell: Cracking the Coding Interview 255 | -------------------------------------------------------------------------------- /ReleaseNotes.md: -------------------------------------------------------------------------------- 1 | # TopJava Release Notes 2 | 3 | ### TopJava 26 4 | - починили шаблоны запросов на создание в Swagger через [ApiModelProperty](https://www.baeldung.com/spring-swagger-hide-field) 5 | - в новой версии Data JPA `getById`->`getReferenceById` 6 | - мелкие правки 7 | 8 | ### TopJava 25 9 | - поправил `NoHtmlValidator`: `Jsoup.clean().equals` -> `Jsoup.isValid` 10 | - починил `role VARCHAR NOT NULL` 11 | - добавил нового тестового пользователя `guest` 12 | 13 | ### TopJava 24 14 | - migrate to LTS JDK 17 15 | - add `AbstractBaseEntity.id()` 16 | - fix for `User.registered`: `@Column(..., updatable = false)` 17 | - add `@QueryHints` in `CrudUserRepository` 18 | - add loggin in `RootController` 19 | - fix `@Sql(.., , executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)` for controller tests after service tests 20 | - rename `MATCHER` to `USER_MATCHER/MEAL_MATCHER` 21 | - treat in `ActiveDbProfileResolver` attribute `profiles` 22 | 23 | ### TopJava 23 24 | - migrate to JDK 16 25 | - в новой spring-data-jpa `getOne` заменили на `getById` 26 | - в UserUtil#prepareToSave убрал проверку пароля на `hasText`. На UI поле проверяется на `@NotBlank` 27 | - `ProfileRestController#register` делаю по правилам REST (POST без "/register") 28 | - css стили `data-...` сделал [low-case через дефисы](https://stackoverflow.com/questions/36176474/548473) 29 | - `TestMatcher` переименовал в `MatcherFactory` 30 | - Для Swagger UI пометил `AuthorizedUser` аннотацией `@ApiIgnore` 31 | 32 | ### TopJava 22 33 | - очистка пароля `AuthorizedUser#userTo` 34 | - заменил `@SafeHtml`, который удалили из `hibernate.validator` на [Jsoup.clean](https://stackoverflow.com/a/68888601/548473) 35 | - перенес запрет на обновление admin/user в `UserService` 36 | - проверку email на уникальность для update с `id=null` в теле запроса сделал на основе анализа `HttpServletRequest.getRequestURI()` 37 | - проверку класса в `classpath` в `Profiles#getActiveDbProfile` делаю на `org.springframework.util.ClassUtils#isPresent` 38 | - удалил `type="text/javascript"` 39 | 40 | ### TopJava 21 41 | - **добавили документирование REST API: Swagger** 42 | - мигрировали на JDK 15 и используем текстовые блоки 43 | - Вынес `produces = MediaType.APPLICATION_JSON_VALUE` на уровень контроллеров 44 | - Правильно используем [глабальные переменные в js](https://stackoverflow.com/a/5064235/548473) 45 | - Зарефакторил `inputField.tag` 46 | - Тестовые переменные переименовал из UPPERCASE в camelCase 47 | - Из тестов сервисов убрал `throws Exception` (в IDEA больше не генерятся по умолчанию) 48 | - **Мигрировали на Spring Boot 2.4.1** 49 | 50 | ### TopJava 20 51 | - мигрировали на JDK 14 52 | - в `@SafeHtml` запрещаем весь html (`whitelistType = NONE`) 53 | - в `topjava.common.js` в `makeEditable()` вместо объекта контекст передаю 3 параметра 54 | - в UI контроллерах убрал префикс `ajax` 55 | - из тестов сервисов убрал `repository`. При проверке через `assertThrows` он не требуется 56 | - в `TestMatcher` сценарии сравнения сделал параметризируемыми (паттерн стратегия) 57 | - в API добавили `/users/{id}/with-meals` (см. [двунаправленные отношения](https://www.codeflow.site/ru/article/jackson-bidirectional-relationships-and-infinite-recursion)) 58 | - добавил `UserTestData.USER_WITH_MEALS_MATCHER` (проверки пользователя сразу с едой) и константу id `NOT_FOUND` 59 | 60 | ### TopJava 19 61 | - Изменилась логика для интервалов времени (исключаем `endTime`) 62 | - Заменил собственный `MessageUtil` велосипед на спринговый `MessageSourceAccessor` 63 | - В ролях убрал префиксы `ROLE_` ([Role and GrantedAuthority](https://stackoverflow.com/a/19542316/548473)) 64 | - Добавился удобный метод `int AbstractBaseEntity.id()` 65 | - Фикс `Location` в `ProfileRestController.register` 66 | - Фикс валидации `UniqueMailValidator` для REST update без `user.id` 67 | - Заменил `jdbc.initLocation` на полный путь - IDEA не ругается 68 | - В конфигурации `cargo-maven2-plugin` сделал [индивидуальный контекст приложения](https://stackoverflow.com/a/60797999/548473) 69 | - Тесты 70 | - Обновил даты еды на 2020г. 71 | - Зарефакторил тесты сервисов на удаление - `NotFoundException` может бросаться при `delete()` 72 | - В тестах контроллеров вернулся к реализации без обертки над `MockMvcRequestBuilders` 73 | - Для `InMemory` тестов подключаю только `inmemory.xml` (добавил туда необходимую конфигурацию из `spring-app.xml`) 74 | 75 | 76 | ### TopJava 18 77 | 78 | - В `ErrorType` добавил `HttpStatus status` 79 | - В PostgreSQL обнаружилась бага: граничное значение `0:00` из-за ошибок округления попадает в предыдущий интервал. 80 | Мораль: всегда в тестах проверяйте граничные значения. Добавил этот случай в тестовые данные. 81 | - Изменил `MealRepository.getBetween` (принимаю `@Nullable LocalDate`). Изменились реализации. 82 | - Выделил метод `UserService.prepareAndSave` 83 | - В TO поля сделал `final`, используем `@ConstructorProperties` 84 | - Наконец локализировал описание приложения на страничке входа 85 | - Для полей ввода дат добавил `autocomplete="off"` 86 | - При закрытии модального окна закрываю окно ошибок 87 | - Тесты: 88 | - **Вместо очистки кэшей перед каждым тестом отключаем кэши для всех тестов** 89 | - **Вынес общий код тестирования контроллеров в `AbstractControllerTest`. Код тестов значительно сократился** 90 | - **Сделал типизированный `TestMatchers` для проверки результатов тестов. В классах `UserTestData` и `MealTestData` создаю его инстансы с заданным типом и методикой сравнения.** 91 | - В тестах `delete` и `create` проверяю результат напрямую (не через `getAll`) 92 | 93 | 94 | ### TopJava 17 95 | - Удалил `Impl` из названий репозиториев 96 | - Удалил интерфейсы к сервисам, использую классы 97 | - Добавил `AdminRestController.enable`, вызов через PATCH метод 98 | - Добавил валидацию для jdbc через Bean Validation API 99 | - Перенес работу в UI с профилем из `RootController` в `ProfileUIController` 100 | - `SLF4JBridgeHandler` инициализирую только в профиле `postgres` 101 | 102 | ### TopJava 16 103 | - Выделил общий код реализации хранения в памяти в `InMemoryBaseRepositoryImpl` 104 | - Сделал подтверждение для удаления записей 105 | - Обновились видео 7-го занятия. [Выложил его как пример занятия, некоторые видео открыты](https://github.com/JavaOPs/topjava/blob/master/doc/lesson07.md) 106 | - Сделали валидации дублирования email через `WebDataBinder` и `Validator` 107 | 108 | ### TopJava 15 109 | - Миграция на Servlet API 4.0 / Tomcat 9.x 110 | - [Миграция на JDK11](http://javaops.ru/view/resources/jdk8_11) 111 | - JUnit5 fix: junit-platform-surefire-provider не нужен 112 | - Рефакторинг тестов: 113 | - в `RootControllerTest.testUsers` для проверки используем `AssertionMatcher` адаптер 114 | - вместо `content().json()` от `jsonassert` десериализуем json и используем сравнения через `AssertJ` 115 | - В javascript место глабальных переменных и одинаковой функции обновления таблицы задаю их в объекте контекст, который передаю в `makeEditable()` как параметр 116 | - Починил `back` в браузере после логина. Кнопки входа и регистрации отображаю только для `isAnonymous()` 117 | 118 | ### TopJava 14 119 | - [Миграция на JUnit 5](http://javaops.ru/view/resources/junit5) 120 | - Для измерения времени в тестах использую [Spring StopWatch](https://www.logicbig.com/how-to/code-snippets/jcode-spring-framework-stopwatch.html) 121 | - `SimpleJdbcInsert` и `NamedParameterJdbcTemplate` конструируются (и берут настройки) из `jdbcTemplate` 122 | - `AuthorizedUser` зарефакторился в `SecurityUtil` 123 | - В javascript [заменил `var` на `let/const`](https://learn.javascript.ru/let-const). [Поддержка 95% браузеров](https://caniuse.com/#feat=const) 124 | - Подправил UI фильтрации и заголовка страниц, добавилась кнопка `Cancel` в профиль 125 | - Починил [баг в FireFox](https://bugzilla.mozilla.org/show_bug.cgi?id=884693): пустой ответ по ajax 126 | - Сделал вход в приложение при нажании кнопок `Зайти как ...` 127 | - Добавил регистрацию пользователя по REST 128 | - Преименовал js файлы согласно [javascript filename naming convention](https://stackoverflow.com/questions/7273316/what-is-the-javascript-filename-naming-convention) 129 | - Сделал проверку startTime/endTime на фильтре времени (после обновления datetimepicker до 2.5.20) 130 | 131 | ### TopJava 13 132 | - [Миграция на Botstrap 4](https://getbootstrap.com/docs/4.1/migration/) 133 | - Добавил [Responsive behaviors](https://getbootstrap.com/docs/4.1/components/navbar/#responsive-behaviors) - при уменшении ширины экрана навигация сворачивается в кнопку 134 | - Для отображения цвета еды и выключенного юзера использую [data-* атрибуты](https://developer.mozilla.org/ru/docs/Web/Guide/HTML/Using_data_attributes) 135 | - В `inputField.tag` передаю как параметр код для локализации label, а в `i18n.jsp` передаю как параметр `page`. См. [JSP include action with parameter example](https://beginnersbook.com/2013/12/jsp-include-with-parameter-example) 136 | 137 | ### TopJava 12 138 | - [Миграция на Spring 5](http://javaops.ru/view/resources/spring5) 139 | - обновил версии: Ehcache 3.x, datatables, datetimepicker 140 | - добавил видео решений HW0 с одним проходом 141 | - поправил видео [Обзор Spring Framework. Spring Context](https://drive.google.com/file/d/1fBSLGEbc7YXBbmr_EwEHltCWNW_pUmIH). Дописал про Constructor injection. 142 | - заменил видео про тетсирование сервисов. Вместо самодельных матчеров стали использовать [AssertJ](http://joel-costigliola.github.io/assertj/index.html). Видео [Тестирование UserService через AssertJ](https://drive.google.com/open?id=1SPMkWMYPvpk9i0TA7ioa-9Sn1EGBtClD), время 1:53 143 | - сделал [видео с jQuery конвертерами и дефолтными группами валидации при сохранении в базу](https://drive.google.com/open?id=1tOMOdmaP5OQ7iynwC77bdXSs-13Ommax) 144 | - сделал [видео с новым `DelegatingPasswordEncoder` и Json READ/WRITE access](https://drive.google.com/file/d/1XZXvOThinzPw4EhigAUdo8-MWT_g8wOt/view?usp=sharing) 145 | - убрал `AccessType.PROPERTY` для `AbstractBaseEntity.id` (см. [fixed HHH-3718](https://hibernate.atlassian.net/browse/HHH-3718)) 146 | - удалил `PasswordUtil`, возвращаю статус `NO_CONTENT` для REST delete, убрал группы валидации в `UserTo` 147 | - заменил в jQuery [success на done](https://stackoverflow.com/a/22213543/548473) 148 | - вместо `lang.jsp` сделал общий `bodyHeader.jsp` 149 | 150 | ### TopJava 11 151 | - добавил 152 | - доп. решение HW1 через одним return и O(N) 153 | - раскрасил лог ([Logback layouts coloring](https://logback.qos.ch/manual/layouts.html#coloring)) 154 | - рефакторинг 155 | - починил коммит формы по cancel (`history.back()`) в FireFox 156 | - заменил неработающий DependencyCi на [VersionEye](https://www.versioneye.com/) c проверкой зависимостей на uptodate 157 | - починил `CrudUserRepository.getWithMeals()` через `@EntityGraph`. С неколькими ролями (у админа) еда дублируется 158 | - починил тесты контроллеров с профилем JDBC (`JpaUtil` отсутствует в контексте JDBC) 159 | - переименовал `meal.jsp/user.jsp` в `mealForm.jsp/userForm.jsp` 160 | - в `InMemoryMealRepositoryImpl.save()` сделал update атомарным 161 | - переименовал методы сервисов `save` в `create` 162 | - переименовал и cделал классы `BaseEntity` и `NamedEntity` абстрактными 163 | - обновил Noty и API с ним до 3.1.0. Добавил glyphicon в сообщения Noty 164 | - заменил `MATCHER_WITH_EXCEED` на валидацию через [JSONassert](https://github.com/skyscreamer/JSONassert). 165 | - поменял Deprecated валидаторы `org.hibernate.validator.constraints` на `javax.validation.constraints` 166 | - убрал пароль из результатов REST через [@JsonProperty READ_ONLY / WRITE_ONLY](https://stackoverflow.com/questions/12505141/only-using-jsonignore-during-serialization-but-not-deserialization/12505165#12505165). Тесты на REST пришлось починить добавлением добавлением в JSON пароля как дополнительного параметра (`JsonUtil.writeWithExtraProps`) 167 | - **убрал JSON View и сделал преобразование времени на UI с помощью [jQuery converters](http://api.jquery.com/jQuery.ajax/#using-converters)** 168 | - **поменял [группу валидации по умолчанию при сохранении через JPA](https://stackoverflow.com/questions/16930623/16930663#16930663).** Теперь 169 | все валидаторы в модели работаю по умолчанию (`groups` не требуется). 170 | - Добавил в `ErrorInfo` тип ошибки `ErrorType` + i18n. 171 | 172 | - правки 173 | - переименовал `ModelMatcher` в `BeanMatcher` и починил: можно сравнивать только упорядоченные коллекции (List) 174 | - поменял зависимость `org.hibernate:hibernate-validator` на `org.hibernate.validator:hibernate-validator` (warning при сборке) 175 | 176 | ### TopJava 10 177 | - добавил 178 | - доступ к AuthorizedUser через [`@AuthenticationPrincipal`](http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#mvc-authentication-principal) и [authentication Tag](http://docs.spring.io/spring-security/site/docs/current/reference/html/taglibs.html#the-authentication-tag) 179 | - [Обработку 404 NotFound](https://stackoverflow.com/questions/18322279/spring-mvc-spring-security-and-error-handling) 180 | - локализацию ошибок валидации 181 | - проверки json в тестах через [JSONassert](https://github.com/skyscreamer/JSONassert) и [через jsonPath](https://www.petrikainulainen.net/programming/spring-framework/integration-testing-of-spring-mvc-applications-write-clean-assertions-with-jsonpath/) 182 | - [логирование от Postgres Driver](http://stackoverflow.com/a/43242620/548473) 183 | - в `.travis.yml` [сборку только ветки master](https://docs.travis-ci.com/user/customizing-the-build#Building-Specific-Branches) 184 | - [защиту от кэширование ajax запросов в IE](https://stackoverflow.com/a/4303862/548473) 185 | - обработку запрета модификации системный юзеров через универсальный `ApplicationException` 186 | - рефакторинг 187 | - сделал `@EntityGraph` через `attributePaths` 188 | - реализаовал обработку дублирования `user.email` и `meal.dateTime` через [Controller Based Exception Handling](https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc#controller-based-exception-handling) 189 | - поменял отключение транзакционности в тестах через `@Transactional(propagation = Propagation.NEVER)` 190 | - сделал выбор в сервлете через switch 191 | - [все логгирование сделал через {} форматирование](http://stackoverflow.com/questions/10555409/logger-slf4j-advantages-of-formatting-with-instead-of-string-concatenation) и поправил его в контроллерах (поле проверки id) 192 | - [перешел на конструктор DI](http://stackoverflow.com/questions/39890849/what-exactly-is-field-injection-and-how-to-avoid-it) 193 | - в `ModelMatcher` переименовал `Comparator` -> `Equality` 194 | - [заинлайнил все лямбды](http://stackoverflow.com/questions/19718353/is-repeatedly-instantiating-an-anonymous-class-wasteful) (компараторы, ModelMatcher.equality) 195 | - поменялась реализация `JdbcUserRepositoryImpl.getAll()` 196 | - на UI кнопки в таблице заменились на линки, поправил сообщения локализации 197 | - [сделал кастомизацию JSON (@JsonView) и валидацию (groups)](https://drive.google.com/file/d/0B9Ye2auQ_NsFRTFsTjVHR2dXczA) для данных еды, отдаваемых на UI 198 | - в `JdbcUserRepositoryImpl` поменял `MapSqlParameterSource` на `BeanPropertySqlParameterSource` 199 | - удалил 200 | - зависимость `javax.transaction.jta` (уже не нужна) 201 | - `${spring.version}` в `pom.xml` зависимостях (уже есть в `spring-framework-bom`) 202 | - distinct из запроса Hibernate на пользователей с ролями. [Оптимизация запроса distinct: 15.16.2](https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#hql-distinct) 203 | - лишние `
` тэги (`shadow` и `view-box`) 204 | 205 | ### TopJava 9 206 | - добавил 207 | - выбор профиля базы через `ActiveProfilesResolver`/`AllActiveProfileResolver` на основе драйвера базы в classpath 208 | - видео Cascade. Auto generate DDL. 209 | - проверку на правильность id в Ajax/Rest контроллерах (treat IDs in REST body) 210 | - тесты на валидацию входных значений контроллеров и зависимость на имплементацию 211 | - Bootstrap Glyphicons 212 | - рефакторинг 213 | - переименовал `TimeUtil` в `DateTimeUtil` 214 | - переименовал `ExceptionUtil` в `ValidationUtil` 215 | - заменил валидацию `@NotEmpty` на `@NotBlank` 216 | - заменил `CascadeType.REMOVE` на `@OnDelete` 217 | - изменил `JdbcUserRepositoryImpl.getAll()` 218 | - обновил jQuery до 3.x, исключил из зависимостей webjars ненужные jQuery 219 | - cделал загрузку скриптов асинхронной 220 | - фильтр еды сделал в [Bootstrap Panels](http://getbootstrap.com/components/#panels) 221 | - вместо `Persistable` ввел интерфейс `HasId` и наследую от него как Entity, так и TO 222 | - сделал универсальную обработку исключений дублирования email и dateTime 223 | 224 | ### TopJava 8 225 | - добавил: 226 | - [защиту от XSS (Cross-Site Scripting)](http://stackoverflow.com/a/40644276/548473) 227 | - интеграцию с Dependency Ci и Travis Ci 228 | - локализацию календаря 229 | - сводку по результатам тестов 230 | - примеры запросов curl в `config/curl.md` 231 | - DataTables/Bootstrap 3 integration 232 | - тесты на профиль деплоя Heroku (общее количество JUnit тестов стало 102) 233 | - удалил зависимость `jul-to-slf4j` 234 | - рефакторинг 235 | - переименовал все классы `UserMeal**` в `Meal**`, JSP 236 | - переименовал `LoggedUser` в `AuthorizedUser` 237 | - починил работа с PK Hibernate в случае ленивой загрузки (баг HHH-3718) 238 | - поменял в `BaseEntity` `equals/hashCode/implements Persistable` 239 | - в `InMemoryMealRepositoryImpl` выделил метод `getAllStream` 240 | - перенес проверки пердусловий `Assert` из `InMemory` репозиториев в сервисы 241 | - переименовал классы _Proxy*_ на более адекватные _Crud*_ 242 | - поменял реализацию `JpaMealRepositoryImpl.get`, добавил в JPA модель `@BatchSize` 243 | - вместо `@RequestMapping` ввел Spring 4.3 аннотации `@Get/Post/...Mapping` 244 | - поменял авторизацию в тестах не-REST контроллеров 245 | - перенес вызовы `UserUtil.prepareToSave` из `AbstractUserController` в `UserServiceImpl` 246 | - зарефакторил обработку ошибок (`ExceptionInfoHandler`) 247 | 248 | ### TopJava 7 249 | - добавил: 250 | - [JPA 2.1 EntityGraph](https://docs.oracle.com/javaee/7/tutorial/persistence-entitygraphs002.htm) 251 | - [Jackson @JsonView](https://habrahabr.ru/post/307392/) 252 | - валидацию объектов REST 253 | - [i18n в JavaScript](http://stackoverflow.com/a/6242840/548473) 254 | - проверку предусловий и видео Методы улучшения качества кода 255 | - интеграцию с проверкой кода в Codacy 256 | - [сравнение вермени исполнения запросов при различных meals индексах](https://drive.google.com/open?id=0B9Ye2auQ_NsFX3RLcnJCWmQ2Y0U) 257 | - tomcat7-maven-plugin плагин перключили на Tomcat 8 (cargo-maven2-plugin) 258 | - рефакторинг 259 | - обработка ошибок сделал с array 260 | - матчеров тестирования (сделал автоматические обертки и сравнение на основе передаваемого компаратора) 261 | - вынес форматирование даты в `functions.tld` 262 | 263 | ### TopJava 3-6 264 | - добавил 265 | - [выпускной проект](https://drive.google.com/open?id=0B9Ye2auQ_NsFcG83dEVDVTVMamc) 266 | - в таблицу meals составной индекс 267 | - константы `Profiles.ACTIVE_DB`, `Profiles.DB_IMPLEMENTATION` 268 | - проверки и тесты на `NotFound` для `UserMealService.getWithUser` и `UserService.getWithMeals` 269 | - в MockMvc фильтр CharacterEncodingFilter 270 | - защиту от межсайтовой подделки запроса, видео Межсайтовая подделка запроса (CSRF) 271 | - ограничение на диапазон дат для фильтра еды 272 | - рефакторинг 273 | - UserMealsUtil, ProfileRestController, компараторов в репозитоии 274 | - `LoggedUser` отнаследовал от `org.springframework.security.core.userdetails.User` 275 | - переименовал `DbTest` в `AbstractServiceTest` и перенес сюда `@ActiveProfiles` 276 | - сделал выполнение скриптов в тестах через аннотацию `@Sql` 277 | - вместо использования id и селектора сделал обработчик `onclick` 278 | - изменил формат ввода даты в форме без 'T' 279 | - убрал 280 | - `LoggerWrapper` 281 | - Dandelion обертку к datatables 282 | - обновил 283 | - Hibernate до 5.x и Hibernate Validator, добавились новые зависимости и `jackson-datatype-hibernate5` 284 | - datatables API (1.10) 285 | - Postgres драйвер. Новый драйвер поддерживает Java 8 Time API, разделил реализацию JdbcMealRepositoryImpl на Java8 (Postgresql) и Timestamp (HSQL) 286 | -------------------------------------------------------------------------------- /cv.md: -------------------------------------------------------------------------------- 1 | ## Составление резюме, подготовка к интервью, поиск работы 2 | 3 | ![cv](https://cloud.githubusercontent.com/assets/13649199/10877471/93ea86b8-8157-11e5-9bfa-95e3fba75c58.jpg) 4 | 5 | - Научиться программировать сложнее, чем кажется 6 | - [Собеседование. Разработка ПО. Вопросы.](https://drive.google.com/file/d/0B9Ye2auQ_NsFQVc2WUdCR0xvLWM/view?usp=sharing&resourcekey=0-HaWoRxoyboMSKjg5P2I1cQ) 7 | - [Набор ссылок для тренировки и прохождения интервью](https://github.com/andreis/interview) 8 | - [Полезные советы Jun-ам](https://github.com/JavaOPs) 9 | 10 | ### Составление резюме: 11 | - [VisualCV: create resume in minutes](https://www.visualcv.com/) 12 | - Выбрать шаблон для резюме 13 | - [GitHub Pages](https://pages.github.com/), Resume template 14 | - Как продать свое резюме в 2 раза дороже 15 | - Как правильно составить резюме 16 | - Резюме программистов. Часть 1 (плохие) 17 | - Резюме программистов. Часть 2 (хорошие) 18 | - Как составить резюме на английском 19 | - ОФОРМЛЕНИЕ IT-РЕЗЮМЕ для USA 20 | 21 | ### Наши истории (делимся опытом и успехом) 22 | 23 | ### Тесты/задачи онлайн: 24 | - [Interviewing: the most profitable skill you can learn (pramp.com)](https://www.pramp.com/) 25 | - [Java Programming Test](https://tests4geeks.com/java) 26 | - game: test Java skills 27 | - Codility lesson tests 28 | - Quizful- тесты онлайн 29 | - LeetCode Online Judge 30 | - Sphere online judge 31 | - Codility programmers lessons 32 | - Hackerrank practice coding 33 | - [start.interviewing.io](https://start.interviewing.io/) 34 | 35 | ## [Тестовое собеседование, самые спрашиваемые темы](http://javaops.ru/interview/test.html) 36 | 37 | ### Интервью: 38 | - [Собеседования для бэкендеров: как готовиться, тренироваться и не облажаться](https://habr.com/ru/companies/getmatch/articles/744760/) 39 | - [10 неочевидных фактов об ИТ-собеседованиях](https://proglib.io/p/molchanie-intervyuera-ili-10-neochevidnyh-faktov-ob-it-sobesedovaniyah-2022-06-14) 40 | - Михаил Портнов. Собеседование на работу: как продать себя грамотно 41 | - Михаил Портнов. Какие вопросы мы задаем на собеседовании? 42 | - Михаил Портнов. Собеседование на работу: жизненный путь 43 | - [Лёша Корепанов. Признаки плохих компаний для программиста](https://www.youtube.com/watch?v=Sj-WSWr-n7U) 44 | - [Лёша Корепанов. Как отвечать на вопросы, которые ты не знаешь. Техническое интервью для программиста](https://www.youtube.com/watch?v=Beoh3tfgPEk) 45 | - Канал: Резюме, поиск работы, интервью 46 | - Яков Файн: Как стать профессиональным Java разработчиком 47 | - Ответы на вопросы на собеседовании Junior Java Developer 48 | - Список вопросов с ответами для собеседования по Java 49 | - Сборка по вопросам на интервью 50 | - Сборка вопросов-ответов от JavaStudy 51 | - [Видео технических интервью от Максима Добрынина](https://www.youtube.com/playlist?list=PLxqzxxW1gWwJvVK11R_lJKAlP_9m3Gu2H) 52 | - [Вопросы по классам коллекциям от JavaRush-1](http://info.javarush.ru/translation/2013/10/08/Часто-задаваемые-на-собеседованиях-вопросы-по-классам-коллекциям-в-Java-Часть-1-.html) 53 | - [Вопросы по классам коллекциям от JavaRush-2](http://info.javarush.ru/translation/2013/10/08/Часто-задаваемые-на-собеседованиях-вопросы-по-классам-коллекциям-в-Java-Часть-2-.html) 54 | - Тест на знание SQL 55 | - Вопросы на собеседовании Java Junior Developer 56 | - Java вопросы с собеседований на Android 57 | - Сборка вопросов от JavaRush 58 | > про clone и finalize объязательно прочтите Джошуа Блох: Java. Эффективное программирование (второе издание) 59 | 60 | - Cracking the Coding Interview 61 | > Особенно обратите внимание на раздел: Часть VIII. Вопросы собеседования 62 | 63 | 64 | ### От себя: 65 | - email, skype - очень желательно, чтобы по ним вы были узнаваемы. Заведите рабочие, если не так. 66 | - написать ВЕСЬ IT опыт (исключая опыт пользователя: Windows, MS Word, Photophop, Yandex disk, Google docs, ..): технологии, какие задачи решали (конкретные), какие инструменты использовали, VCS, DB, инструменты сборки, ... включая опыт в ВУЗе. 67 | - на English иметь желательно. Если вакансия опублинована на Englsih - шлите на нем. Часто могут на нем попросить, если работодатель иностранный. 68 | - удобно иметь резюме где-то в Интернете (hh, linkedin, google doc, чтобы им было удобно делиться). 69 | 70 | ### Позиционирование проекта TopJava: 71 | - Обязательно убери из резюме **любое упоминание Junior**. Количество обращений возрастет на порядок. Ссылку на стажировку можно поставить: http://javaops.ru/view/topjava (в linkedin: https://www.linkedin.com/company/java-online-projects). 72 | - После завершения проекта ты освоишь все заявленные в нем технологии - вставь их в квалификацию (включая Java 8 Stream and Time API). 73 | - В разделе опыт работы (если нет коммерческого опыта) вставь: 74 | 75 | Участие в разработке Spring/JPA Enterprise приложения c авторизацией и правами доступа на основе ролей 76 | на стеке Maven/ Spring MVC/ Security/ REST(Jackson)/ Java 8 Stream API: 77 | - реализация сохранения в базы Postgres и HSQLDB на основе Spring JBDC, JPA(Hibernate) и Spring-Data-JPA 78 | - реализация и тестирование REST и AJAX контроллеров 79 | - реализация клиента на Bootstrap (css/js), DataTables, jQuery + plugins. 80 | - собственная доработка проекта 81 | 82 | - Делай упор не на обучение, а на **участие в проекте**. Выполнение домашних заданий это полноценное участие с написанием функционала по всем пройденным технологиям. На собеседовании смотрят не на то, что ты заканчивал, а на опыт и знания. 83 | 84 | ### В процессе обучения 85 | - Если рассматриваешь предложения по работе, подними в своем профиле этот флаг и обязательно заполни ссылку на резюме. Обновления нашей базы выпускников смотрят уже более 125 партнеров по трудоустройству (компании и индивидуальные рекрутеры). Проверь содержание "Информация для HR": по нему принимают решение, открывать резюме или нет. 86 | 87 | - Вступайте в нашу группу участников Slack: каналы помощи с Java, отзывы о работодателях, обсуждение тестовых заданий, вакансии, цены на рынке труда, IT события, интересные видео и многое другое. 88 | 89 | - Подпишитесь на рассылку вакансий под себя 90 | 91 | ### После прохождения испытательного срока жду твою [историю успеха](http://javaops.ru/view/story) 92 | 93 | ### Основные сайты поиска работы: 94 | - [Актуальная подборка Junior вакансий от CodeReview](https://jobs.yourcodereview.com?utm_source=partner&utm_medium=javaops&utm_campaign=landing) 95 | - Яндекс агрегатор 96 | - HH 97 | - LinkedIn 98 | - ХабрКарьера 99 | - [headz.io](https://app.headz.io/candidates/new) 100 | - djinni.co (более актуально для Украины) 101 | 102 | [Как изучать Java. Подборка от JavaRush](https://javarush.ru/groups/posts/3538-v-zakladki-kak-izuchatjh-java-boljhshaja-podborka-po-planu-obuchenija-instrumentam-i-poiskam-mo) 103 |

Как выжить на испытательном сроке

104 | 105 | - Учись грамотно формулировать проблему. Проблема "у меня не работает" может иметь тысячи причин. В 106 | процессе формулирования очень часто приходит ее решение. 107 | - Учись инвестигировать проблему. Внимательное чтение логов и умение дебажить - основные навыки 108 | разработчика. В логах надо читать верх самого нижнего эксепшена - там причина всей портянки. 109 | - Грамотно уделяй время каждой проблеме. Две крайности: сразу бросаться за помощью и 110 | биться над проблемой часами. 111 | Пробуй решить ее сам и, в зависимости от проблемы, выделяй на это разумное время. 112 | - Не бросайся сразу писать код, поищи в проекте схожий функционал! И далее - минимум своих подходов, если хотите внести что-то свое - обязательно спросите! 113 | Проект должен быть однотипным по максимуму во всех мелочах: - описание, пакеты, имена классов и методов и даже переменных, реализация, хелп. 114 | Обычно можно найти сходный функционал, взять его себе и делать в нем изменения под свою реализацию. 115 | - Если тебе что-то объясняют по проекту - обязательно записывай. 116 | - Когда получаешь задачу - уточни все очень подробно. Если задач несколько - обязательно выясни приоритеты! 117 | - Получай в процессе решения обратную связь - в том ли направлении ты идешь 118 | - Не игнорируй совместные ланчи (курилки) 119 | - Готовься к стендапам/летучкам. Задавай на них вменяемые вопросы. Выказывай заинтересованность 120 | - Выдели самое главное путем опроса босса и важных коллег. Не распыляйся на мелочи. 121 | - [**5 вещей, которые разработчик должен сделать прежде чем попросить о помощи**](https://techrocks.ru/2018/07/16/5-things-a-developer-should-do-before-asking-for-help/) 122 | - [**Советы новичкам**](https://blog.csssr.com/ru/article/how-to-be-a-beginner-developer) 123 | - [ТОП-13 ошибок начинающего программиста](https://proglib.io/p/beginners-fails/) 124 | - [25 ошибок начинающего программиста](https://habr.com/ru/post/413129/) 125 | - [Путеводитель по синдрому самозванца](https://vc.ru/hr/167443-eshche-odin-putevoditel-po-sindromu-samozvanca-korni-prichiny-simptomy-i-posledstviya-chast-1) 126 | - [Нетехнические навыки](https://tproger.ru/experts/softskills-for-job) 127 | - Видео [Junior и испытательный срок на первой работе](https://www.youtube.com/watch?v=GsGlsCbok-c) 128 | - Типичные ошибки начинающих программистов от JavaRush: 129 | - [Часть 1](https://javarush.ru/groups/posts/3044-razbor-tipichnihkh-oshibok-nachinajujshikh-programmistov-chastjh-1) 130 | - [Часть 2](https://javarush.ru/groups/posts/3055-razbor-tipichnihkh-oshibok-nachinajujshikh-programmistov-chastjh-2) 131 | - [От джуна к миддлу: практические советы](https://tproger.ru/articles/ot-dzhuna-k-middlu-prakticheskie-sovety) 132 | ## [Отзывы по стажировке TopJava](https://vk.com/topic-74381644_30447246) 133 | -------------------------------------------------------------------------------- /description.md: -------------------------------------------------------------------------------- 1 | #### Разработка полнофункционального Spring/JPA Enterprise приложения c авторизацией и правами доступа на основе ролей с использованием наиболее популярных инструментов и технологий Java: Maven, Spring MVC, Security, JPA(Hibernate), REST(Jackson), Bootstrap (css, js), DataTables, jQuery + plugins, Java 8 Stream and Time API и сохранением в базах данных PostgreSQL и HSQLDB. 2 | 3 | - Основное внимание будет уделяться способам решения многочисленных проблем разработки в Spring/JPA, а также структурному (красивому и надежному) java-кодированию и архитектуре приложения. 4 | - Каждая итерация проекта закрепляется домашним заданием по реализации схожей функциональности. Следующее занятие начинается с разбора домашних заданий. 5 | - Большое внимание уделяется тестированию кода: в проекте более 100 JUnit-тестов. 6 | - Несмотря на относительно небольшой размер, приложение разрабатывается с нуля как большой проект: например, используем кэш 2-го уровня Hibernate, настраиваем Jackson для работы с ленивой загрузкой Hibernate, делаем конвертеры для типов LocalDateTime (Java 8 time API). 7 | - Разбираются архитектурные паттерны: слои приложения и как правильно разбивать логику по слоям, когда нужно применять Data Transfer Object. То есть на выходе получается не учебный проект, а хорошо масштабируемый шаблон для большого проекта на всех пройденных технологиях. 8 | - Большое внимание уделяется деталям: популяция базы данных, использование транзакционности, тесты сервисов и REST-контроллеров, настройка EntityManagerFactory, выбор реализации пула коннектов. Особое внимание уделяется работе с базой данных: через Spring JDBC, Spring ORM и Spring Data Jpa. 9 | - Используются самые востребованные на сегодняшний момент фреймворки: Maven, Spring Security 4 вместе с Spring Security Test, наиболее удобный для работы с базой проекта Spring Data Jpa, библиотека логирования Logback, реализующая SLF4J, повсеместно используемый Bootstrap и jQuery. 10 | 11 | #### Демо разрабатываемого приложения 12 | 13 | ## План проекта (ссылки на некоторые темы открыты для просмотра) 14 | ### Архитектура проекта. Персистентность. 15 | - Системы управления версиями 16 | - Java 8: Lambda, Stream API 17 | - Обзор используемых в проекте технологий и инструментов. 18 | - Инструмент сборки Maven 19 | - WAR. Веб-контейнер Tomcat. Сервлеты. 20 | - Логирование. 21 | - Обзор стандартных библиотек. Apache Commons, Guava 22 | - Слои приложения. Создание каркаса приложения. 23 | - Обзор Spring Framework. Spring Context. 24 | - Тестирование через JUnit. 25 | - Spring Test 26 | - Базы данных. PostgreSQL. Обзор NoSQL и Java persistence solution без ORM. 27 | - Настройка Database в IDEA. 28 | - Скрипты инициализации базы. Spring Jdbc Template. 29 | - Spring: инициализация и популирование БД 30 | - ORM. Hibernate. JPA. 31 | - [Тестирование JPA-сервиса через AssertJ](https://www.youtube.com/watch?v=BlyaXT6tOaw) 32 | - Поддержка HSQLDB 33 | - Транзакции 34 | - Профили Maven и Spring 35 | - Пул коннектов 36 | - Spring Data JPA 37 | - Кэш Hibernate 38 | 39 | ### Разработка WEB 40 | - Spring кэш 41 | - Spring Web 42 | - JSP, JSTL, i18n 43 | - Tomcat maven plugin. JNDI 44 | - Spring Web MVC 45 | - Spring Internationalization 46 | - Тестирование Spring MVC 47 | - REST-контроллеры 48 | - Тестирование REST-контроллеров. Jackson. 49 | - jackson-datatype-hibernate. Тестирование через матчеры. 50 | - Тестирование через SoapUi. UTF-8 51 | - WebJars. 52 | - Bootstrap. jQuery datatables. 53 | - AJAX. jQuery. Notifications. 54 | - Spring Security 55 | - Spring Binding/Validation 56 | - Работа с DataTables через Ajax. 57 | - Spring Security Test 58 | - [Кастомизация JSON (@JsonView) и валидации (groups)](https://drive.google.com/file/d/0B9Ye2auQ_NsFRTFsTjVHR2dXczA/view?usp=sharing&resourcekey=0-Ou4A_gRor5HaRho4Fciqdw) 59 | - Encoding password 60 | - CSRF (добавление в проект защиты от межсайтовой подделки запроса) 61 | - form-login. Spring Security Taglib 62 | - Handler interceptor 63 | - Spring Exception Handling 64 | - Смена локали 65 | - Фильтрация JSON с помощью @JsonView 66 | - Защита от XSS (Cross Site Scripting) 67 | - Деплой на [собственный выделенный сервер](https://github.com/JavaOPs/startup) 68 | - Локализация datatables, ошибок валидации 69 | - Обработка ошибок 404 (NotFound) 70 | - Доступ к AuthorizedUser 71 | - Собеседование. Разработка ПО 72 | 73 | ### Миграция на Spring Boot 74 | - Основы Spring Boot. Spring Boot maven plugin 75 | - Lombok, база H2, ApplicationRunner 76 | - Spring Data REST + HATEOAS 77 | - Swagger/ OpenAPI 3.0 78 | - Тестирование и кэширование в Spring Boot 79 | - Миграция приложения TopJava на Spring Boot 80 | -------------------------------------------------------------------------------- /doc/lesson07.md: -------------------------------------------------------------------------------- 1 | # [Онлайн стажировка Spring 5/JPA Enterprise (TopJava)](http://javaops.ru/view/topjava) 2 | ## [Почему мы?](http://javaops.ru/#why) 3 | 4 | ## REST, REST-контроллеры, тестирование контроллеров Spring MVC 5 | # Для просмотра открыты видео [4](#--4-миграция-на-junit-5), [5](#-5-принципы-rest-rest-контроллеры), [6](#-6-тестирование-rest-контроллеров-jackson), [7](#-7-кастомизация-jackson-object-mapper), [8](#user-content--8-тестирование-rest-контроллеров-через-jsonassert-и-матчеры) 6 | - Не стоит стремиться прочитать все ссылки урока, их можно использовать как справочник. Гораздо важнее пройти основной материал урока и сделать домашнее задание 7 | - Обязательно посмотри правила работы с патчами на проекте 8 | - Делать Apply Patch лучше по одному непосредственно перед видео на эту тему, а при просмотре видео сразу отслеживать все изменения кода проекта по изменению в патче (`Version Control -> Local Changes -> Ctrl+D`) 9 | - При первом Apply удобнее выбрать имя локального ченджлиста Name: Default. Далее все остальные патчи также будут в него попадать. 10 | - Код проекта обновляется и не всегда совпадает с видео (можно увидеть, как развивался проект). Изменения в проекте указываю после соответствующего патча. 11 | 12 | ## ![hw](https://cloud.githubusercontent.com/assets/13649199/13672719/09593080-e6e7-11e5-81d1-5cb629c438ca.png) Разбор домашнего задания HW6 13 | 14 | ### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 1. HW6 15 | #### Apply 7_01_HW6_fix_tests.patch 16 | 17 | #### Apply 7_02_HW6_meals.patch 18 | 19 | > сделал фильтрацию еды через `get`: операция идемпотентная, можно делать в браузере обновление по F5 20 | 21 | ### Внимание: чиним пути в следующем патче 22 | 23 | #### Apply 7_03_HW6_fix_relative_url_utf8.patch 24 | 25 | - 26 | Relative paths in JSP 27 | - 28 | Spring redirect: prefix 29 | 30 | ### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 2. HW6 Optional 31 | 32 | #### Apply 7_04_HW6_optional_add_role.patch 33 | 34 | #### `JdbcUserServiceTest` отвалились. Будем чинить в `7_06_HW6_jdbc_transaction_roles.patch` 35 | 36 | #### Apply 7_05_fix_hint_graph.patch 37 | 38 | - В `JpaUserRepositoryImpl.getByEmail` DISTINCT попадает в запрос, хотя он там не нужен. Это просто указание Hibernate 39 | не дублировать данные. Для оптимизации можно указать Hibernate делать запрос без 40 | distinct: [15.16.2. Using DISTINCT with entity queries](https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#hql-distinct) 41 | - Бага [HINT_PASS_DISTINCT_THROUGH does not work if 'hibernate.use_sql_comments=true'](https://hibernate.atlassian.net/browse/HHH-13280). При `hibernate.use_sql_comments=false` все работает - в SELECT нет DISTINCT. 42 | - Тест `DataJpaUserServiceTest.getWithMeals()` не работает для admin (у админа 2 роли, и еда при JOIN дублируется). ... 43 | 44 | #### Apply 7_06_HW6_jdbc_transaction_roles.patch 45 | 46 | Еще интересные JDBC реализации: ... 47 | 48 | ### Валидация для `JdbcUserRepository` через Bean Validation API 49 | 50 | #### Apply 7_07_HW6_optional_jdbc_validation.patch 51 | 52 | - [Валидация данных при помощи Bean Validation API](https://alexkosarev.name/2018/07/30/bean-validation-api/). 53 | 54 | На данный момент у нас реализована валидация сущностей только для jpa- и dataJpa-репозиториев. При работе 55 | через JDBC-репозиторий может произойти попытка записи в БД некорректных данных, что приведет к `SQLException` из-за нарушения 56 | ограничений, наложенных на столбцы базы данных. Для того чтобы перехватить невалидные данные еще до 57 | обращения в базу, воспользуемся API *javax.validation* (ее реализация `hibernate-validator` используется для проверки данных в Hibernate и будет использоваться в Spring Validation, которую подключим позже). 58 | В `ValidationUtil` создадим один потокобезопасный валидатор, который можно переиспользовать (см. *javadoc*). 59 | С его помощью в методах сохранения и обновления сущности в jdbc-репозиториях мы можем производить валидацию этой сущности: `ValidationUtil.validate(object);` 60 | Чтобы проверка не падала, `@NotNull Meal.user` пришлось пока закомментировать. Починим в 10-м занятии через `@JsonView`. 61 | 62 | ### Отключение кэша в тестах: 63 | 64 | Вместо наших приседаний с `JpaUtil` и проверкой профилей мы можем ... 65 | 66 | #### Apply 7_08_HW06_optional2_disable_tests_cache.patch 67 | 68 | - [Example of PropertyOverrideConfigurer](https://www.concretepage.com/spring/example_propertyoverrideconfigurer_spring) 69 | - [Spring util schema](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#xsd-schemas-util) 70 | 71 | ## Занятие 7: 72 | 73 | ### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 3. Тестирование Spring MVC 74 | 75 |
76 | Краткое содержание 77 | 78 | #### Тестирование Spring MVC 79 | 80 | Для более удобного сравнения объектов в тестах мы будем использовать библиотеку *Harmcrest* с Matcher'ами, которая 81 | позволяет делать сложные проверки. С *JUnit* по умолчанию подтягивается *Harmcrest core*, но нам потребуется расширенная версия: 82 | в `pom.xml` из зависимости JUnit исключим дочернюю `hamcrest-core` и добавим `hamcrest-all`. 83 | 84 | Для тестирования web создадим вспомогательный класс `AbstractControllerTest`, от которого будут наследоваться все 85 | тесты контроллеров. Его особенностью будет наличие `MockMvc` - эмуляции Spring MVC для тестирования web-компонентов. 86 | Инициализируем ее в методе, отмеченном `@PostConstruct`: 87 | 88 | ``` 89 | mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).addFilter(CHARACTER_ENCODING_FILTER).build(); 90 | ``` 91 | 92 | Для того чтобы в тестах контроллеров не популировать базу перед каждым тестом, пометим этот базовый тестовый класс аннотацией `@Transactional`. 93 | Теперь каждый тестовый метод будет выполняться в транзакции, которая будет откатываться после окончания метода и возвращать базу данных в исходное 94 | состояние. Однако теперь в работе тестов могут возникнуть нюансы, связанные с пропагацией транзакций: все 95 | транзакции репозиториев станут вложенными во внешнюю транзакцию теста. При этом, например, кэш первого уровня станет работать не 96 | так, как ожидается. Т. е. при таком подходе нужно быть готовыми к ошибкам: мы их увидим и поборем в тестах на обработку ошибок на последних занятиях TopJava. 97 | 98 | #### UserControllerTest 99 | 100 | Создадим тестовый класс для контроллера юзеров, он должен наследоваться от `AbstractControllerTest`. 101 | В `MockMvc` используется [паттерн проектирования Builder](https://refactoring.guru/ru/design-patterns/builder). 102 | 103 | ``` 104 | mockMvc.perform(get("/users")) // выполнить HTTP метод GET к "/users" 105 | .andDo(print()) // распечатать содержимое ответа 106 | .andExpect(status().isOk()) // от контроллера ожидается ответ со статусом HTTP 200(ok) 107 | .andExpect(view().name("users")) // контроллер должен вернуть view с именем "users" 108 | .andExpect(forwardedUrl("/WEB-INF/jsp/users.jsp")) // ожидается, что клиент должен быть перенаправлен на "/WEB-INF/jsp/users.jsp" 109 | .andExpect(model().attribute("users", hasSize(2))) // в модели должен быть атрибут "users" размером = 2 ... 110 | .andExpect(model().attribute("users", hasItem( // ... внутри которого есть элемент ... 111 | allOf( 112 | hasProperty("id", is(START_SEQ)), // ... с аттрибутом id = START_SEQ 113 | hasProperty("name", is(USER.getName())) //... и name = user 114 | ) 115 | ))); 116 | } 117 | ``` 118 | 119 | В параметры метода `andExpect()` передается реализация `ResultMatcher`, в которой мы определяем, как должен быть обработан ответ контроллера. 120 | 121 |
122 | 123 | #### Apply 7_09_controller_test.patch 124 | 125 | > - в `MockMvc` добавился `CharacterEncodingFilter` 126 | > - добавил [`AllActiveProfileResolver`](//http://stackoverflow.com/questions/23871255/spring-profiles-simple-example-of-activeprofilesresolver) для возвращения массива профилей 127 | > - сделал вспомогательный метод `AbstractControllerTest.perform()` 128 | 129 | - Hamcrest 130 | - Unit Testing of Spring MVC Controllers 131 | 132 | ### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 4. [Миграция на JUnit 5](https://drive.google.com/open?id=16wi0AJLelso-dPuDj6xaGL7yJPmiO71e) 133 | 134 |
135 | Краткое содержание 136 | 137 | Для миграции на 5-ю версию JUnit в файле `pom.xml` поменяем зависимость `junit` на `junit-jupiter-engine` ([No need `junit-platform-surefire-provider` dependency in `maven-surefire-plugin`](https://junit.org/junit5/docs/current/user-guide/#running-tests-build-maven)). 138 | Актуальную версию всегда можно посмотреть [в центральном maven-репозитории](https://search.maven.org/search?q=junit-jupiter-engine), берем только релизы (..-Mx означают предварительные milestone версии) 139 | Изменять конфигурацию плагина `maven-sureface-plugin` в новых версиях JUnit уже не требуется. 140 | JUnit5 не содержит в себе зависимости от *Harmcrest* (которую нам приходилось вручную 141 | отключать для JUnit4 в предыдущих шагах), поэтому исключение `hamcrest-core` просто удаляем. 142 | В итоге у нас останутся зависимости JUnit5 и расширенный Harmcrest. 143 | Теперь мы можем применить все нововведения пятой версии в наших тестах: 144 | 1. Для всех тестов теперь мы можем удалить `public`. 145 | 2. Аннотацию `@Before` исправим на `@BeforeEach` - теперь метод, который будет выполняться перед 146 | каждым тестом, помечается именно так. 147 | 3. В JUnit5 работа с исключениями похожа на JUnit4 версии 4.13: вместо ожидаемых исключений в параметрах аннотации `@Test(expected = Exception.class)` используется метод `assertThrows()`, 148 | в который первым аргументом мы передаем ожидаемое исключение, а вторым аргументом — реализацию функционального интерфейса `Executable` (код, 149 | в котором ожидается возникновение исключения). 150 | 4. Метод `assertThrows()` возвращает исключение, которое было выброшено в переданном ему коде. Теперь мы можем получить это исключение, извлечь из него сообщение с помощью 151 | `e.getMessage()` и сравнить с ожидаемым. 152 | 5. Для теста на валидацию при проверке предусловия, только при выполнении которого 153 | будет выполняться следующий участок кода (например, в нашем случае тесты на валидацию выполнялись 154 | только в jpa профиле), теперь нужно пользоваться утильным методом `Assumptions` (нам уже не требуется). 155 | 6. Проверку Root Cause - причины, из-за которой было выброшено пойманное исключение, мы будем делать позднее, при тестах на ошибки. 156 | 7. Из JUnit5 исключена функциональность `@Rule`, вместо них теперь нужно использовать `Extensions`, которые 157 | могут встраиваться в любую фазу тестов. Чтобы добавить их в тесты, пометим базовый тестовый класс аннотацией `@ExtendWith`. 158 | 159 | JUnit предоставляет нам набор коллбэков — интерфейсов, которые будут исполняться в определенный момент тестирования. 160 | Создадим класс `TimingExtension`, который будет засекать время выполнения тестовых методов. 161 | Этот класс будет имплементировать маркерные интерфейсы — коллбэки JUnit: 162 | - `BeforeTestExecutionCallback` - коллбэк, который будет вызывать методы этого интерфейса перед каждым тестовым методом. 163 | - `AfterTestExecutionCallback` - методы этого интерфейса будут вызываться после каждого тестового метода; 164 | - `BeforeAllCallback` - методы перед выполнением тестового класса; 165 | - `AfterAllCallback` - методы после выполнения тестового класса; 166 | 167 | Осталось реализовать соответствующие методы, которые описываются в каждом из этих интерфейсов, они и будут вызываться JUnit в нужный момент: 168 | - в методе `beforeAll` (который будет вызван перед запуском тестового класса) создадим спринговый утильный секундомер `StopWatch` для текущего тестового класса; 169 | - в методе `beforeTestExecution` (будет вызван перед тестовым методом) - запустим секундомер; 170 | - в методе `afterTestExecution` (будет вызван после тестового метода) - остановим секундомер. 171 | - в методе `afterAll` (который будет вызван по окончанию работы тестового класса) - выведем результат работы этого секундомера в лог; 172 | 173 | 8. Аннотации `@ContextConfiguration` и `@ExtendWith(SpringExtension.class)` (замена `@RunWith`) мы можем заменить одной `@SpringJUnitConfiguration` (старые версии IDEA ее не понимают) 174 | 175 |
176 | 177 | #### Apply 7_10_JUnit5.patch 178 | 179 | > - [No need `junit-platform-surefire-provider` dependency in `maven-surefire-plugin`](https://junit.org/junit5/docs/current/user-guide/#running-tests-build-maven) 180 | > - [Наконец пофиксили баг с `@SpringJUnitConfig`](https://youtrack.jetbrains.com/issue/IDEA-166549) 181 | 182 | - [JUnit 5 homepage](https://junit.org/junit5) 183 | - [Overview](https://junit.org/junit5/docs/snapshot/user-guide/#overview) 184 | - [10 интересных нововведений](https://habr.com/post/337700) 185 | - Дополнительно: 186 | - [Extension Model](https://junit.org/junit5/docs/current/user-guide/#extensions) 187 | - [A Guide to JUnit 5](http://www.baeldung.com/junit-5) 188 | - [Migrating from JUnit 4](http://www.baeldung.com/junit-5-migration) 189 | - [Before and After Test Execution Callbacks](https://junit.org/junit5/docs/snapshot/user-guide/#extensions-lifecycle-callbacks-before-after-execution) 190 | - [Conditional Test Execution](https://junit.org/junit5/docs/snapshot/user-guide/#writing-tests-conditional-execution) 191 | - [Third party Extensions](https://github.com/junit-team/junit5/wiki/Third-party-Extensions) 192 | - [Реализация assertThat](https://stackoverflow.com/questions/43280250) 193 | 194 | ### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 5. [Принципы REST. REST контроллеры](https://drive.google.com/open?id=1e4ySjV15ZbswqzL29UkRSdGb4lcxXFm1) 195 | 196 |
197 | Краткое содержание 198 | 199 | #### Принципы REST, REST-контроллеры 200 | 201 | > [REST](http://spring-projects.ru/understanding/rest/) - архитектурный стиль проектирования распределенных систем (типа клиент-сервер). 202 | 203 | Чаще всего в REST-сервер и клиент общаются посредством обмена JSON-объектами через HTTP-методы GET/POST/PUT/DELETE/PATCH. 204 | Особенностью REST является отсутствие состояния (контекста) взаимодействий клиента и сервера. 205 | 206 | В нашем приложении есть контроллеры для Admin и для User. Чтобы сделать их REST-контроллерами, 207 | заменим аннотацию `@Controller` на `@RestController` 208 | 209 | > Не поленитесь зайти через Ctrl+click в `@RestController`: к аннотации `@Controller` добавлена `@ResponseBody`. Т. е. ответ от нашего приложения будет не View, а данные в теле ответа. 210 | 211 | В `@RequestMapping`, кроме пути для методов контроллера (`value`), добавляем параметр `produces = MediaType.APPLICATION_JSON_VALUE`. 212 | Это означает, что в заголовки ответа будет добавлен тип `ContentType="application/json"` - в ответе от контроллера будет приходить JSON-объект. 213 | 214 | > Чтобы было удобно использовать путь к этому контроллеру в приложении и в тестах, 215 | > выделим путь к нему в константу REST_URL, к которой можно будет обращаться из других классов 216 | 217 | 1. Метод `AdminRestController.getAll` пометим аннотацией `@GetMapping` - маршрутизация к методу по HTTP GET. 218 | 219 | 2. Метод `AdminRestController.get` пометим аннотацией `@GetMapping("/{id}")`. 220 | В скобках аннотации указано, что к основному URL контроллера будет добавляться `id` пользователя - переменная, которая передается в запросе непосредственно в URL. 221 | Соответствующий параметр метода нужно пометить аннотацией `@PathVariable` (если имя в URL и имя аргумента метода не совпадают, в параметрах аннотации дополнительно нужно будет уточнить 222 | имя в URL. Если они совпадают, [этого не требуется](https://habr.com/ru/post/440214/). 223 | 224 | 3. Метод создания пользователя `create` отметим аннотацией `@PostMapping` - маршрутизация к методу по HTTP POST. 225 | В метод мы передаем объект `User` в теле запроса (аннотация `@RequestBody`) в формате JSON (`consumes = MediaType.APPLICATION_JSON_VALUE`). 226 | При создании нового ресурса правило хорошего тона - вернуть в заголовке ответа URL созданного ресурса. 227 | Для этого возвращаем не `User`, а `ResponseEntity`, который мы можем с помощью билдера `ServletUriComponentsBuilder` дополнить заголовком ответа `Location` и вернуть статус `CREATED(201)` 228 | (если пойти в код `ResponseEntity.created` можно докопаться до сути, очень рекомендую смотреть в исходники кода). 229 | 230 | 4. Метод `delete` помечаем `@DeleteMapping("/{id}")` - HTTP DELETE. 231 | Он ничего не возвращает, поэтому помечаем его аннотацией `@ResponseStatus(HttpStatus.NO_CONTENT)`. Статус ответа будет HTTP.204; 232 | 233 | 5. Над методом обновления ставим `@PutMapping` (HTTP PUT). В аргументах метод принимает `@RequestBody User user` и `@PathVariable int id`. 234 | 235 | 6. Метод поиска по `email` также помечаем `@GetMapping` и, чтобы не было конфликта маршрутизации с методом `get()`, 236 | указываем в URL добавку `/by`. В этот метод `email` передается как параметр запроса (аннотация `@RequestParam`). 237 | 238 | > **Все это СТАНДАРТ архитектурного стиля REST. НЕ придумывайте ничего своего в своих выпускных проектах! Это очень большая ошибка - не придерживаться стандартов API.** 239 | 240 | 7. `ProfileRestController` выполняем аналогичным способом с учетом того, что пользователь имеет доступ только к своим данным. 241 | 242 | Если на данном этапе попытаться запустить приложение и обратиться к какому-либо методу контроллера, сервер ответит нам ошибкой со статусом 406, 243 | так как Spring не знает, как преобразовать объект User в JSON... 244 | 245 |
246 | 247 | #### Apply 7_11_rest_controller.patch 248 | 249 | - Понимание REST 250 | - JSON (JavaScript Object Notation) 251 | - [15 тривиальных фактов о правильной работе с протоколом HTTP](https://habrahabr.ru/company/yandex/blog/265569/) 252 | - [10 Best Practices for Better RESTful](https://medium.com/@mwaysolutions/10-best-practices-for-better-restful-api-cbe81b06f291) 253 | - [Best practices for rest nested resources](https://stackoverflow.com/questions/20951419/what-are-best-practices-for-rest-nested-resources) 254 | - 255 | Request mapping 256 | - [Лучшие практики разработки REST API: правила 1-7,15-17](https://tproger.ru/translations/luchshie-praktiki-razrabotki-rest-api-20-sovetov/) 257 | - Дополнительно: 258 | - [Подборка практик REST](https://gist.github.com/Londeren/838c8a223b92aa4017d3734d663a0ba3) 259 | - JAX-RS vs Spring MVC 260 | - RESTful API для сервера – делаем правильно (Часть 1) 261 | - RESTful API для сервера – делаем правильно (Часть 2) 262 | - И. Головач. 263 | RestAPI 264 | - [value/name в аннотациях @PathVariable и @RequestParam](https://habr.com/ru/post/440214/) 265 | 266 | ### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 6. [Тестирование REST контроллеров. Jackson.](https://drive.google.com/open?id=1aZm2qoMh4yL_-i3HhRoyZFjRAQx-15lO) 267 | 268 |
269 | Краткое содержание 270 | 271 | Для работы с JSON добавляем в `pom.xml` зависимость `jackson-databind`. 272 | Актуальную версию библиотеки можно посмотреть в [центральном maven-репозитории](https://search.maven.org/artifact/com.fasterxml.jackson.core/jackson-databind). 273 | Теперь Spring будет автоматически использовать эту библиотеку для сериализации/десериализации объектов в JSON (найдя ее в *classpath*). 274 | Если сейчас запустить приложение и обратиться к методам REST-контроллера, то оно выбросит `LazyInitializationException`. 275 | Оно возникает из-за того, что у наших сущностей есть лениво загружаемые поля, отмеченные `FetchType.LAZY` - при загрузке сущности из базы вместо такого поля подставится Proxy, который и должен вернуть 276 | реальный экземпляр этого поля при первом же обращении. Jackson при сериализации в JSON использует все поля сущности, 277 | и при обращении к *Lazy*-полям возникает исключение, так как сессия работы с БД в этот момент уже закрыта, и нужный объект 278 | не может быть инициализирован. Чтобы Jackson игнорировал эти поля, пометим их аннотацией `@JsonIgnore`. 279 | 280 | Теперь при запуске приложения REST-контроллер будет работать. Но при получении JSON-объектов мы можем увидеть, что Jackson сериализовал объект 281 | через геттеры (например, в ответе есть поле `new` от метода `Persistable.isNew()`). 282 | Чтобы учитывались только поля объектов, добавим над `AbstractBaseEntity`: 283 | ````java 284 | @JsonAutoDetect(fieldVisibility = ANY, // jackson видит все поля 285 | getterVisibility = NONE, // ... но не видит геттеров 286 | isGetterVisibility = NONE, //... не видит геттеров boolean-полей 287 | setterVisibility = NONE) // ... не видит сеттеров 288 | ```` 289 | Теперь все сущности, унаследованные от базового класса, будут сериализоваться/десериализоваться через поля. 290 | 291 |
292 | 293 | #### Apply 7_12_rest_test_jackson.patch 294 | 295 | - [Jackson databind github](https://github.com/FasterXML/jackson-databind) 296 | - [Jackson Annotation Examples](https://www.baeldung.com/jackson-annotations) 297 | 298 | ### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 7. [Кастомизация Jackson Object Mapper](https://drive.google.com/open?id=1CM6y1JhKG_yeLQE_iCDONnI7Agi4pBks) 299 | 300 |
301 | Краткое содержание 302 | 303 | Сейчас, чтобы не сериализовать *Lazy*-поля, мы должны пройтись по каждой сущности и 304 | вручную пометить их аннотацией `@JsonIgnore`. Это неудобно, засоряет код и допускает возможные ошибки. К тому же, 305 | при некоторых условиях, нам иногда нужно загрузить и в ответе передать эти *Lazy*-поля. 306 | Чтобы запретить сериализацию Lazy-полей для всего проекта, подключим в `pom.xml` библиотеку `jackson-datatype-hibernate`. 307 | Также изменим сериализацию/десериализацию полей объектов в JSON: не через аннотацию `@JsonAutoDetect`, а в классе `JacksonObjectMapper`, который 308 | унаследуем от `ObjectMapper` (стандартный Mapper, который использует Jackson) и сделаем в нем другие настройки. 309 | В конструкторе: 310 | - регистрируем `Hibernate5Module` - модуль `jackson-datatype-hibernate`, который не делает сериализацию ленивых полей. 311 | - модуль для корректной сериализации `LocalDateTime` в поля JSON - `JavaTimeModule` модуль библиотеки `jackson-datatype-jsr310` 312 | - запрещаем доступ ко всем полям и методам класса и потом разрешаем доступ только к полям 313 | - не сериализуем null-поля (`setSerializationInclusion(JsonInclude.Include.NON_NULL)`) 314 | 315 | Чтобы подключить наш кастомный `JacksonObjectMapper` в проект, в конфигурации `spring-mvc.xml` к 316 | настройке `` добавим `MappingJackson2HttpMessageConverter`, который будет использовать наш маппер. 317 | 318 |
319 | 320 | 321 | #### Apply 7_13_jackson_object_mapper.patch 322 | 323 | - Сериализация hibernate lazy-loading с помощью 324 | jackson-datatype-hibernate 325 | - Handle Java 8 dates with Jackson 326 | - Дополнительно: 327 | - Jackson JSON 328 | Serializer & Deserializer 329 | 330 | ### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 8. [Тестирование REST-контроллеров через JSONassert и Матчеры](https://drive.google.com/open?id=1oa3e0_tG57E71g6PW7_tfb3B61Qldctl) 331 | 332 |
333 | Краткое содержание 334 | 335 | Сейчас в тестах REST-контроллера мы проводим проверку только на статус ответа и тип возвращаемого контента. Добавим проверку содержимого ответа. 336 | 337 | #### 7_14_json_assert_tests 338 | 339 | Чтобы сравнивать содержимое ответа контроллера в виде JSON и сущность, воспользуемся библиотекой 340 | `jsonassert`, которую подключим в `pom.xml` со scope *test*. 341 | 342 | Эта библиотека при сравнении в тестах в качестве ожидаемого значения ожидает от 343 | нас объект в виде JSON-строки. Чтобы вручную не преобразовывать объекты в JSON и не 344 | хардкодить их в виде строк в наши тесты, воспользуемся Jackson. 345 | Для преобразования объектов в JSON и обратно создадим утильный класс `JsonUtil`, в котором 346 | с помощью нашего `JacksonObjectMapper` и будет конвертировать объекты. 347 | И мы сталкиваемся с проблемой: `JsonUtil` - утильный класс и не является 348 | бином Spring, а для его работы требуется наш кастомный маппер, который находится под управлением 349 | Spring и расположен в контейнере зависимостей. Поэтому, чтобы была возможность получить 350 | наш маппер из других классов, сделаем его синглтоном и сделаем в нем статический 351 | метод, который будет возвращать его экземпляр. Теперь `JsonUtil` сможет его получить. 352 | И нам нужно указать Spring, чтобы он не создавал второй экземпляр этого объекта, а клал в свой контекст существующий. 353 | Для этого в конфигурации `spring-mvc.xml` определим factory-метод, с помощью которого Spring должен 354 | получить экземпляр (instance) этого класса: 355 | ```xml 356 | 357 | ``` 358 | а в конфигурации `message-converter` вместо создания бина просто сошлемся на сконфигурированный `objectMapper`. 359 | 360 | Метод `ContentResultMatchers.json()` из `spring-test` использует библиотеку `jsonassert` для сравнения 2-х JSON строк: одну из ответа контроллера и вторую - 361 | JSON-сериализация `admin` без поля `registered` (это поле инициализируется в момент создания и отличается). 362 | В методе `JsonUtil.writeIgnoreProps` мы преобразуем объект `admin` в мапу, удаляем из нее игнорируемые поля и снова сериализуем в JSON. 363 | 364 | Также сделаем тесты для утильного класса `JsonUtil`. В тестах мы записываем 365 | объект в JSON-строку, затем конвертируем эту строку обратно в объект и сравниваем с исходным. И то же самое делаем со списком объектов. 366 | 367 | #### 7_15_tests_refactoring 368 | 369 | **`RootControllerTest`** 370 | 371 | Сделаем рефакторинг `RootControllerTest`. Ранее мы в тесте получали модель, доставали из нее сущности и с помощью `hamcrest-all` 372 | производили по одному параметру их сравнение с ожидаемыми значениями. 373 | Метод `ResultActions.andExpect()` позволяет передавать реализацию интерфейса `Matcher`, в котором можно делать любые сравнения. 374 | Функциональность сравнения списка юзеров по ВСЕМ полям у нас уже есть - мы просто делегируем сравнение объектов в `UserTestData.MATCHER`. 375 | При этом нам больше не нужен `harmcrest-all`, нам достаточно только `harmcrest-core`. 376 | 377 | **`MatcherFactory`** 378 | 379 | Теперь вместо `jsonassert` и сравнения JSON-строк в тестах контроллеров сделаем сравнения JSON-объектов через `MatcherFactory`. 380 | Преобразуем ответ контроллера из JSON в объект и сравним с эталоном через уже имеющийся у нас матчер. 381 | Вместо сравнения JSON-строк в метод `andExpect()` мы будем передавать реализации интерфейса `ResultMatcher` из `MATCHER.contentJson(..)`. 382 | 383 | `MATCHER.contentJson(..)` принимают ожидаемый объект и возвращают для него `ResultMatcher` с реализацией единственного метода `match(MvcResult result)`, 384 | в котором делегируем сравнение уже существующим у нас матчерам. 385 | Мы берем JSON-тело ответа (`MatcherFactory.getContent`), десериализуем его в объект (`JsonUtil.readValue/readValues`) и сравниваем через имеющийся `MATCHER.assertMatch` 386 | десериализованный из тела контроллера объект и ожидаемое значение. 387 | 388 | > Методы из класса `TestUtil` перенес в `MatcherFactory`, лишние удалил. 389 | 390 | **`AdminRestControllerTest`** 391 | 392 | - `getByEmail()` - сделан по аналогии с тестом `get()`. Дополнительно нужно добавить в строку URL параметры запроса. 393 | - `delete()` - выполняем HTTP.DELETE. Проверяем статус ответа 204. Проверяем, что пользователь удален. 394 | 395 | > Раньше я получал всех users из базы и проверял, что среди них нет удаленного. При этом тесты становятся чувствительными ко всем users в базе и ломаются при добавлении/удалении новых тестовых данных. 396 | 397 | - `update()` - выполняем HTTP.PUT. В тело запроса подаем сериализованный `JsonUtil.writeValue(updated)`. После выполнения проверяем, что объект в базе обновился. 398 | - `create()` - выполняем HTTP.POST аналогично `update()`. Но сравнить результат мы сразу не можем, т. к. при создании объекта ему присваивается `id`. 399 | Поэтому мы извлекаем созданного пользователя из ответа (`MATCHER.readFromJson(action)`), получаем его `id`, и уже с этим `id` эталонный объект мы можем сравнить с объектом в ответе контроллера и со 400 | значением в базе. 401 | - `getAll()` - аналогично `get()`. Список пользователей из ответа в формате JSON сравниваем с эталонным списком (`MATCHER.contentJson(admin, user)`). 402 | 403 | Тесты для `ProfileRestController` выполнены аналогично. 404 | 405 |
406 | 407 | #### Apply 7_14_json_assert_tests.patch 408 | 409 | > - В `JsonUtil.writeIgnoreProps` вместо цикла по мапе сделал `map.keySet().removeAll` 410 | 411 | - [JSONassert](https://github.com/skyscreamer/JSONassert) 412 | - [Java Code Examples for ObjectMapper](https://www.programcreek.com/java-api-examples/index.php?api=com.fasterxml.jackson.databind.ObjectMapper) 413 | 414 | #### Apply 7_15_tests_refactoring.patch 415 | 416 | > - Методы из класса `TestUtil` перенес в `MatcherFactory`, лишние удалил. 417 | > - Раньше в тестах я для проверок получал всех users из базы и сравнивал с эталонным списком. При этом тесты становятся чувствительными ко всем users в базе и ломаются при добавлении/удалении новых тестовых данных. 418 | 419 | - [Java @SafeVarargs Annotation](https://www.baeldung.com/java-safevarargs) 420 | 421 | ### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 9. Тестирование через SoapUI. UTF-8 422 | 423 |
424 | Краткое содержание 425 | 426 | SoapUI - это один из инструментов для тестирования API приложений, которые работают по REST и по SOAP. 427 | Он позволяет нам по протоколу HTTP дернуть методы нашего API и увидеть ответ контроллеров. 428 | 429 | Если в контроллер мы добавим метод, который в теле ответа будет возвращать текст на кириллице, то увидим, что кодировка теряется. 430 | Для сохранения кодировки используем `StringHttpMessageConverter`, который конфигурируем в `spring-mvc.xml`. 431 | При этом мы должны явно указать, что конвертор будет работать только с текстом в кодировке *UTF-8*. 432 | 433 |
434 | 435 | #### Apply 7_16_soapui_utf8_converter.patch 436 | 437 | - Инструменты тестирования REST: 438 | - SoapUI 439 | - Написание HTTP-запросов с помощью 440 | Curl. 441 | Для Windows 7 можно использовать Git Bash, с Windows 10 v1803 можно прямо из консоли. Возможны проблемы с UTF-8: 442 | - [CURL doesn't encode UTF-8](https://stackoverflow.com/a/41384903/548473) 443 | - [Нстройка кодировки в Windows](https://support.socialkit.ru/ru/knowledge-bases/4/articles/11110-preduprezhdenie-obnaruzhenyi-problemyi-svyazannyie-s-raspoznavaniem-russkih-simvolov) 444 | - **[IDEA: Tools->HTTP Client->...](https://www.jetbrains.com/help/idea/rest-client-tool-window.html)** 445 | - Postman 446 | - [Insomnia REST client](https://insomnia.rest/) 447 | 448 | **Импортировать проект в SoapUI из `config\Topjava-soapui-project.xml`. Response смотреть в формате JSON.** 449 | 450 | > Проверка UTF-8: http://localhost:8080/topjava/rest/profile/text 451 | 452 | [ResponseBody and UTF-8](http://web.archive.org/web/20190102203042/http://forum.spring.io/forum/spring-projects/web/74209-responsebody-and-utf-8) 453 | 454 | ## ![question](https://cloud.githubusercontent.com/assets/13649199/13672858/9cd58692-e6e7-11e5-905d-c295d2a456f1.png) Ваши вопросы 455 | 456 | > Зачем у нас и UI-контроллеры, и REST-контроллеры? То есть в общем случае backend-разработчику недостаточно предоставить REST API и RestController? 457 | 458 | В общем случае нужны и те, и другие. REST обычно используют для отдельного UI (например, на React или Angular) или для 459 | интеграции / мобильного приложения. У нас REST-контроллеры используются только для тестирования. UI-контроллеры используем для 460 | нашего приложения на JSP шаблонах. Таких сайтов без богатой UI логики тоже немало. Например https://javaops.ru/ :) 461 | Разница в запросах: 462 | 463 | - для UI используются только GET и POST 464 | - при создании/обновлении в UI мы принимаем данные из формы `application/x-www-form-urlencoded` (посмотрите 465 | вкладку `Network`, не в формате JSON) 466 | - для REST API запросы GET, POST, PUT, DELETE, PATCH и возвращают только данные (обычно JSON) 467 | 468 | ...и в способе авторизации: 469 | 470 | - для REST API у нас будет базовая авторизация 471 | - для UI - через cookies 472 | 473 | Также часто бывают смешанные сайты, где есть и отдельное JS приложение, и шаблоны. 474 | 475 | > При выполнении тестов через MockMvc никаких изменений на базе не видно, почему оно не сохраняет? 476 | 477 | `AbstractControllerTest` аннотируется `@Transactional` - это означает, что тесты идут в транзакции, и после каждого 478 | теста JUnit делает rollback базы. 479 | 480 | > Что получается в результате выполнения запроса `SELECT DISTINCT(u) FROM User u LEFT JOIN FETCH u.roles ORDER BY u.name, u.email`? В чем разница в SQL без `DISTINCT`. 481 | 482 | Запросы SQL можно посмотреть в логах. Т. е. `DISTINCT` в `JPQL` влияет на то, как Hibernate обрабатывает дублирующиеся 483 | записи (с `DISTINCT` их исключает). Результат можно посмотреть в тестах или приложении, поставив брекпойнт. По 484 | поводу `SQL DISTINCT` не стесняйтесь пользоваться google, 485 | например, [оператор SQL DISTINCT](http://2sql.ru/novosti/sql-distinct/) 486 | 487 | > В чем заключается расширение функциональности hamcrest в нашем тесте, что нам пришлось его отдельно от JUnit прописывать? 488 | 489 | hamcrest-all используется в проверках `RootControllerTest`: `org.hamcrest.Matchers.*` 490 | 491 | > Jackson мы просто подключаем в помнике, и Spring будет с ним работать без любых других настроек? 492 | 493 | Да, Spring смотрит в classpath и если видит там Jackson, то подключает интеграцию с ним. 494 | 495 | > Где-то слышал, что любой ресурс по REST должен однозначно идентифицироваться через url без параметров. Правильно ли задавать URL для фильтрации в виде `http://localhost/topjava/rest/meals/filter/{startDate}/{startTime}/{endDate}/{endTime}` ? 496 | 497 | Так делают только при 498 | отношении 499 | агрегация, например, если давать админу право смотреть еду любого юзера, URL мог бы быть похож 500 | на `http://localhost/topjava/rest/users/{userId}/meals/{mealId}` (не рекомендуется, см. ссылку ниже). В случае критериев 501 | поиска или страничных данных они передаются как параметр. Смотри также: 502 | 503 | - [15 тривиальных фактов о правильной работе с протоколом HTTP](https://habrahabr.ru/company/yandex/blog/265569/) 504 | - 10 Best Practices 505 | for Better RESTful 506 | - [REST resource hierarchy (если кратко: не рекомендуется)](https://stackoverflow.com/questions/15259843/how-to-structure-rest-resource-hierarchy) 507 | 508 | > Что означает конструкция в `JsonUtil`: `reader.readValues(json)`; 509 | 510 | См. Generic Methods. Когда компилятор 511 | не может вывести тип, можно его уточнить при вызове generic метода. Неважно, static или нет. 512 | 513 | ## ![hw](https://cloud.githubusercontent.com/assets/13649199/13672719/09593080-e6e7-11e5-81d1-5cb629c438ca.png) Домашнее задание HW07 514 | 515 | - 1: Добавить тесты контроллеров: 516 | - 1.1 `RootControllerTest.getMeals` для `meals.jsp` 517 | - 1.2 Сделать `ResourceControllerTest` для `style.css` (проверить `status` и `ContentType`) 518 | - 2: Реализовать `MealRestController` и протестировать его через `MealRestControllerTest` 519 | - 2.1 следите, чтобы url в тестах совпадал с параметрами в методе контроллера. Можно добавить 520 | логирование `` для проверки маршрутизации. 521 | - 2.2 в параметрах `getBetween` принимать `LocalDateTime` (конвертировать 522 | через @DateTimeFormat with Java 523 | 8 Date-Time API), пока без проверки на `null` (используя `toLocalDate()/toLocalTime()`, см. Optional п. 3). В 524 | тестах передавать в формате `ISO_LOCAL_DATE_TIME` ( 525 | например `'2011-12-03T10:15:30'`). 526 | 527 | ### Optional 528 | 529 | - 3: Переделать `MealRestController.getBetween` на параметры `LocalDate/LocalTime` c раздельной фильтрацией по 530 | времени/дате, работающий при `null` значениях (см. демо и `JspMealController.getBetween`) 531 | . Заменить `@DateTimeFormat` на свои LocalDate/LocalTime конверторы или форматтеры. 532 | - Spring Type 533 | Conversion 534 | - Spring Field 535 | Formatting 536 | - 537 | Difference between Spring MVC formatters and converters 538 | - 4: Протестировать `MealRestController` (SoapUI, Curl, IDEA Test RESTful Web Service, Postman). Запросы `curl` занести 539 | в отдельный `md` файл (или `README.md`) 540 | - 5: Добавить в `AdminRestController` и `ProfileRestController` методы получения пользователя вместе с 541 | едой (`getWithMeals`, `/with-meals`). 542 | - [Jackson – Bidirectional Relationships](https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion) 543 | 544 | ### Optional 2 545 | 546 | - 6: Сделать тесты на методы контроллеров `getWithMeals()` (п. 5) 547 | 548 | **На следующем занятии используется JavaScript/jQuery. Если у вас там 549 | пробелы, пройдите его основы** 550 | --------------------- 551 | 552 | ## ![error](https://cloud.githubusercontent.com/assets/13649199/13672935/ef09ec1e-e6e7-11e5-9f79-d1641c05cbe6.png) Типичные ошибки и подсказки по реализации 553 | 554 | - 1: Ошибка в тесте _Invalid read array from JSON_ обычно расшифровывается немного ниже: читайте внимательно. 555 | - 2: Jackson и неизменяемые объекты (для 556 | сериализации `MealTo`) 557 | - 3: Если у meal, приходящий в контроллер, поля `null`, проверьте `@RequestBody` перед параметром (данные приходят в 558 | формате JSON) 559 | - 4: При проблемах с собственным форматтером убедитесь, что в конфигурации `[JVM Ecosystem Report 2021](https://snyk.io/jvm-ecosystem-report-2021/) 38 | >показывает, что Spring является абсолютным 39 | >лидером среди фреймворков. 40 | 41 | На первом месте упоминается **Spring Boot**, а на втором - **Spring MVC**. 42 | 43 | Здесь хотелось бы внести некоторую ясность. 44 | "Сердцем" Spring является Spring Core, который реализует Dependency 45 | Injection. 46 | Этот компонент, как правило, используется во всех остальных 47 | проектах Spring Framework. 48 | 49 | Spring Boot - это надстройка над Spring Framework, 50 | которая позволяет быстро создавать приложения разных типов, 51 | использовать автоматическую конфигурацию для некоторых 52 | компонентов и использовать некоторые удобные встроенные 53 | инструменты, например, готовые инструменты для мониторинга 54 | работы приложения (Spring Actuator). 55 | 56 | Если мы создаем web-приложение, то мы можем создавать его с 57 | помощью Spring Boot, но Spring MVC, который является именно 58 | web-фреймворком, также будет присутствовать в таком приложении 59 | и играть ключевую роль. 60 | 61 | Spring Boot позволяет создавать очень простые приложения без 62 | единой строчки конфигурации. Но как только мы пытаемся 63 | создать что-то более сложное, нам все равно приходится 64 | создавать конфигурационные файлы и классы и настраивать все вручную 65 | точно так же, как в традиционном Spring-приложении. 66 | По своему опыту могу сказать, что на реальных проектах 67 | такая ситуация возникает в большинстве случаев. 68 | Например, как только нужно настроить подключение 69 | к нескольким базам данных, а не к одной, мы вынуждены 70 | создавать конфигурационные классы вручную. 71 | 72 | В этом случае Spring Boot в какой-то степени может даже 73 | навредить вашей продуктивности, потому что вам придется 74 | разбираться, какие автоконфигурационные классы отключить, и т. д. 75 | 76 | Мы изучаем Spring довольно глубоко. 77 | Традиционно хорошо показал себя подход, при котором 78 | вначале изучается чистый Spring Framework, после чего 79 | мы переходим к использованию Spring Boot. Такой подход 80 | сохраняется и в этой версии курса. Без этого Spring Boot 81 | будет для вас "черным ящиком", который вам будет очень 82 | сложно понять, настраивать и отлаживать. 83 | 84 | ### ORM frameworks 85 | Отчеты, которые мы использовали, обычно не включают информацию 86 | о самых популярных ORM-фреймворках. 87 | 88 | >Известно, 89 | >что **Hibernate** является достаточно популярным фреймворком 90 | >и наиболее часто упоминается в вакансиях, если сравнивать 91 | >его с другими ORM-фреймворками и инструментами для работы Java-приложения 92 | >с базами данных. 93 | 94 | Вот одна из статей, которая также говорит о 95 | популярности Hibernate: [Top 5 Java ORM tools - 2022](https://www.knowledgefactory.net/2021/09/top-java-orm-tools-20XX.html) 96 | 97 | **ORM** или **Object-relational-mapping** можно перевести как 98 | "объектно-реляционное отображение (преобразование)". 99 | Это техника, которая позволяет создать виртуальную базу 100 | данных с помощью объектно ориентированного языка 101 | программирования и взаимодействовать с ней, в то время 102 | как взаимодействие уже с реальной базой данных выполняется 103 | фреймворком незаметно для нас. 104 | Это облегчает работу, позволяет работать с привычными 105 | и удобными для использования Java-объектами, вызывая 106 | их методы, вместо того, чтобы писать SQL-запросы к базе данных и код для интерпретации полученных данных. 107 | 108 | >Hibernate является реализацией спецификации JPA, 109 | >так же, как и менее популярный EclipseLink. 110 | 111 | Говоря простым языком, JPA (Java Persistence API) - это 112 | набор интерфейсов без реализации для работы с ORM, 113 | который включен в стандарт Java EE. Отдельные провайдеры 114 | могут предоставлять свои реализации этого интерфейса. 115 | 116 | Недостатками JPA и его реализации Hibernate являются удар по производительности 117 | и недостаточная гибкость. Вопрос производительности частично 118 | может быть решен с помощью различных техник оптимизации кода, 119 | написанного с использованием JPA, однако для некоторых 120 | приложений тот оверхед, который несет в себе JPA, является 121 | недопустимым, и вы можете увидеть на некоторых проектах 122 | использование других подходов, от использования 123 | чистого JDBC до использования MyBatis, JOOQ или каких-то 124 | альтернативных решений. 125 | 126 | В реальных приложениях те запросы к базе данных, 127 | которые создают наибольшую нагрузку на систему, 128 | могут быть оптимизированы для улучшения производительности: для 129 | них могут быть применены JDBC, альтернативные 130 | JPA-фреймворки, также запросы могут быть написаны 131 | с помощью нативных SQL-запросов в JPA. 132 | Для остальных запросов, которые не приводят к 133 | большой нагрузке на систему, в том же приложении может 134 | быть применен Hibernate. 135 | Таким образом, в одном приложении могут быть применены одновременно разные технологии. 136 | 137 | 138 | На курсе вы изучите, как работать с БД с помощью нескольких 139 | технологий: JDBC (а точнее, Spring JDBC template), 140 | а также JPA и Spring DataJPA. 141 | Вы сами не только увидите, но и почувствуете 142 | при написании кода в ваших домашних заданиях плюсы и минусы каждого подхода. 143 | 144 | ### Обзор пройденных тем 145 | Давайте подведем промежуточные итоги по результатам этого урока. 146 | 147 | В этом уроке мы: 148 | 149 | * познакомились с тем, что такое фреймворки 150 | и для чего они нужны; 151 | * посмотрели статистику, которая определяет 152 | Spring Framework как самый популярный фреймворк на рынке; 153 | * познакомились с ORM - подходом для упрощения работы 154 | с базами данных с использованием объектно-ориентированного подхода; 155 | * узнали про JPA (Java Persistence API) - протокол для работы с 156 | ORM - и про реализации JPA, среди которых Hibernate является самой популярной; 157 | * обсудили недостатки подхода ORM и познакомились с инструментами, 158 | которые могут быть использованы в качестве альтернативы. 159 | 160 | В следующем коротком уроке мы завершим обзор используемых технологий. 161 | Увидимся в следующем видео. 162 | -------------------------------------------------------------------------------- /doc/video2.3.md: -------------------------------------------------------------------------------- 1 | ## Обзор наиболее востребованных технологий. Тренды 2 | 3 | ## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) [Видео](https://drive.google.com/file/d/1XcTRkArj2guek9OiPuFEq_U1V4Dg0N-j) 4 | 5 | ### Тренд на отказ от reflection 6 | 7 | Говоря о трендах, хотелось бы сказать, что в настоящее 8 | время развиваются фреймворки, построенные на отказе 9 | от использования Reflection API. 10 | Dependency injection в Spring, сериализация с помощью 11 | Jackson построены на использовании Reflection, что 12 | сильно бьет по производительности, но было достаточно 13 | удобным решение до недавнего времени. 14 | Фреймворк Micronaut полностью построен на отказе от 15 | Reflection, и это дает существенный прирост 16 | производительности при измерении ряда параметров. 17 | Micronaut использует продвинутый компилятор и 18 | генерацию байткода, что позволяет создать все 19 | бины (управляемые фреймворком объекты) в ходе компиляции. 20 | 21 | Пока доля Micronaut очень мала, но он используется 22 | в продакшене. Я предполагаю, что в какой-то момент 23 | Spring может также внедрить подобный подход. 24 | 25 | ### Тренд на развитие реактивного программирования 26 | 27 | Продолжает развиваться реактивное программирование, 28 | которое является в какой-то степени новой парадигмой 29 | в программировании. 30 | 31 | Spring развивает свой реактивный фреймворк Spring WebFlux, 32 | который поддерживает библиотеку Reactor. 33 | 34 | 35 | Ряд современных задач не решается традиционными 36 | методами, такими как блокирующий Input/Output, 37 | HTTP-протокол. Одним из решений данных вопросов 38 | является применение подходов реактивного 39 | программирования (Reactor, RxJava), использование 40 | новых протоколов передачи данных (RSocket). 41 | У нас также готовится курс [ReactJava](https://javaops.ru/#inprogress) как 42 | продолжение TopJava на реактивном стеке. 43 | 44 | ### Тренд на микросервисы, тезисы 45 | 46 | ПО становиться большим и сложным. Очень большое приложение 47 | сложно поддерживать одной командой, управлять его жизненным 48 | циклом - разработкой, релизами. 49 | 50 | Если в большое монолитное приложение добавляется новая 51 | функциональность приходиться выполнять повторного тестирование 52 | всей большой системы, в результате срок выхода новых фич увеличивается. 53 | 54 | Микросервисная архитектура позволяет решить эту проблему - она 55 | предполагает разделение большого приложения на отдельные 56 | приложения-модули, которые взаимодействуют друг с другом. 57 | Над одним модулем-сервисом может работать один человек или 58 | небольшая команда. У такого модуля-сервиса будет отдельный 59 | Git-репозиторий, он может быть задеплоен (развернут) независимо 60 | от остальной системы. При таком подходе, команды могут вести работу 61 | над различными сервисами параллельно, параллельно деплоить 62 | их на серверах. При внесении изменений в микросервис “А”, 63 | вероятность вызывать проблемы в микросервисе “B” снижается. 64 | У разных микросервисов могут быть собственные базы данных. 65 | Это также повышает надежность и гибкость. Например, если по каким то причинам после обновления банковского микросервиса, ответственного за выдачу кредитов возникли сбои и база данных оказалась недоступна, другие компоненты системы, имеющие отдельные базы данных, продолжат свою работу без сбоев. 66 | 67 | Это существенно упрощает доработку, тестирование и деплой таких систем. 68 | 69 | Использование микросервисов дает большую гибкость в выборе 70 | технологий. Нам не нужно ограничивать себя в использовании 71 | технологий для того, чтобы все стандартизировать внутри 72 | одной большой системы. Работая с отдельными микросервисами, 73 | мы можем выбрать идеально подходящие технологии для отдельных задач. 74 | Например, один микросервис может использовать реляционные 75 | базы данных, а второй эффективнее решает свою задачу 76 | используя NoSQL базу данных или in memory базу данных. 77 | 78 | Еще одно важное преимущество, которое дает микросервисная 79 | архитектура это возможность легко масштабировать систему горизонтально. 80 | 81 | Предположим, что банк испытывает быстрый рост обращений 82 | об открытии новых счетов. 83 | 84 | Если банк использует монолитную архитектуру, 85 | то есть одно большое приложение, ему может потребоваться 86 | запускать отдельный экземпляр всего своего приложения 87 | и направлять часть обращений от клиентов на этот экземпляр (instance). 88 | 89 | Если же банк использует микросервисную архитектуру, 90 | он может запустить несколько экземпляров только сервиса, 91 | ответственного за открытие новых счетов и распределять 92 | нагрузку между этими экземплярами. 93 | При этом микросервис, ответственный за выдачу кредитов, 94 | который не испытывает повышенной нагрузки, может остаться 95 | в одном экземпляре. При этом увеличение числа микросервисов, 96 | ответственных за открытие счетов может происходить автоматически 97 | с помощью инструментов DevOps и Kubernetes. 98 | 99 | Однако использование микросервисов также создает сложности. 100 | Разработка систем, построенных на микросервисной архитектуре 101 | на порядок сложнее. Обслуживание таких систем также 102 | существенно сложнее. 103 | 104 | Компания должна обслуживать множество серверов, 105 | обеспечивать мониторинг каждого микросервиса и так далее. 106 | Также security таких систем существенно сложнее, 107 | поскольку мы имеем дело с множеством приложений, 108 | коммуницирующих друг с другом и все эти коммуникации 109 | должны быть безопасными. 110 | 111 | 112 | Следующий, готовый стать самым популярным 113 | после TopJava курс - [Микросервисы](https://javaops.ru/view/cloudjava). 114 | 115 | [Первое занятие открытое](https://javaops.ru/view/cloudjava/lesson01) 116 | -------------------------------------------------------------------------------- /doc/video2.4.md: -------------------------------------------------------------------------------- 1 | ## 2.4 Обзор наиболее востребованных технологий. Обзор разрабатываемого приложения 2 | 3 | ## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) [Видео](https://drive.google.com/file/d/1LHI18LZK1MRIEBpVe3WjCE890EydN5Gz) 4 | 5 | ### О работе с фронтендом и JavaScript 6 | Курс включает себя минимальную практику работы с JavaScript. 7 | Почему это нужно? 8 | В вакансиях backend разработчиков, как правило, отсутствуют 9 | требования глубокого знания JavaScript, но каждый разработчик 10 | должен уметь пользовать DevTools - инструментами разработчика 11 | в браузере, чтобы при работе над рабочими задачами по меньшей 12 | мере иметь возможность понять, происходит ли ошибка на стороне 13 | фронтенда или на стороне бэкенда, увидеть, какие данные уходят 14 | на сервер с фронтенда и так далее. 15 | 16 | Также, конечно, минимальные знания JavaScript приятны, поскольку 17 | они дают вам возможность написать свой несложный проект хотя 18 | бы с минимальным фронтендом. 19 | 20 | Существуют также fullstack-разработчики, от которых требуется 21 | способность полноценно решать задачи фронтенда на продакшене. 22 | Это требует довольно глубокого знания фронтенд-технологий и 23 | таких фреймворков, как Angular или React. Это требует много 24 | времени, и такая подготовка не входит в курс TopJava. -------------------------------------------------------------------------------- /doc/video3.md: -------------------------------------------------------------------------------- 1 | ## Рекомендуемые подходы обучения на курсе 2 | 3 | ## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) [Видео](https://drive.google.com/file/d/1v5sVL8ivNvSXEPVlrYibFLD5byywRkmT) 4 | 5 | В предыдущих уроках мы сделали обзор технологий, 6 | которые будут использоваться в нашем курсе и создаваемом проекте. 7 | Теперь давайте поговорим о том, как начать 8 | изучать эти технологии и практиковаться в их использовании. 9 | 10 | --- 11 | В 1980 году National Training Laboratories в 12 | США провели исследования эффективности разных 13 | способов обучения. 14 | Выяснилось, что у лекций и чтения книг крайне 15 | низкая эффективность — всего 5-10%. 16 | Дальше идет просмотр видео лекций и прослушивание аудио. 17 | 18 | Максимальная эффективность в 90% — это обучение 19 | людьми других людей — менторинг и немедленное 20 | применение полученных знаний на практике. 21 | 22 | 23 | 24 | 25 | 26 | Я хочу подчеркнуть этот момент. 27 | 28 | >Когда вы смотрите видео, вам может казаться, что вы все понимаете, но, поверьте, когда вы попытаетесь повторить это самостоятельно, у вас возникнет множество вопросов и сложностей. Практика - это важнейшая часть обучения, не пропускайте ее. 29 | 30 | На нашем курсе мы: 31 | - обсуждаем занятия с коллегами и преподавателями в Slack - эффективность 50% 32 | - выполняем практические домашние задания по каждой пройденной теме - 75% 33 | - помогаем коллегам и разрабатываем собственный выпускной проект - 90% 34 | 35 | ### О проверке домашних заданий 36 | Также очень важная часть обучения - проверка 37 | ваших домашних заданий и ревью выпускного 38 | проекта нашими кураторами. 39 | 40 | >**Это самый эффективный способ научиться программировать!** 41 | 42 | При устройстве на работу, на собеседовании обязательно 43 | задавай вопрос про ревью кода. 44 | Если его нет, фирма занимается разработкой 45 | непрофессионально? и рост там будет достаточно 46 | медленным и ограниченным. 47 | 48 | В ревью укажут именно твои ошибки 49 | в стиле, структурах данных, алгоритмах и кодировании. 50 | До вечера вторника участники шлют ссылку 51 | на свой GitHub-репозиторий с домашним 52 | заданием занятия, проверка делается 53 | ассистентами, результат пишется в Slack. 54 | Получается эффективно и оперативно. 55 | 56 | После проверки можно исправить замечания 57 | и пройти ее еще раз. 58 | 59 | В конце стажировки делается ревью вашего выпускного проекта. 60 | 61 | 62 | ### Участие на стажировке: ожидания и реальность 63 | 64 | Давайте кратко обсудим, чем курс TopJava является 65 | и чем он не является, что следует от него ожидать 66 | и чего не следует. 67 | 68 | #### 1-й тип ложного представления о стажировке: 69 | 70 | >Я увижу, как с нуля строится web-приложение A с использованием технологий B, просмотрю видео по темам, этого будет достаточно 71 | 72 | 73 | 74 | Почему такой подход не верный: 75 | TopJava - это стажировка, поэтому НЕ рассчитывайте 76 | пройти ее на диване с пакетом поп-корна. 77 | Тебе придется на ней РАБОТАТЬ (выполнять ДЗ, 78 | самостоятельно решать какие-то задачи, читать логи, 79 | дебажить, ходить на StackOverflow и даже думать 80 | об этом, засыпая) 81 | 82 | #### 2-й тип ложного представления о стажировке: 83 | >Меня научат шаблонам работы с технологией А, и я 84 | > смогу их применять в любой ситуации 85 | 86 | Почему это тоже не вполне верный подход: 87 | Используемые на стажировке технологии представляют 88 | собой инструменты, которые позволяет сделать 89 | что-то проще. Мы поделимся практикой их использования, 90 | неочевидными особенностями и т. п., покажем 91 | "грабли", на которые вы рано или поздно наступите. 92 | Нет гарантии, что, устроившись на работу, вы 93 | увидите точно такие же подходы. 94 | Все проекты и команды индивидуальны: используются 95 | различные инструменты и различные решения. 96 | Столкновение с технологиями, с которыми 97 | ты ранее не был знаком, - это нормальная 98 | часть жизни любого программиста. Нужно быть к этому готовым. 99 | 100 | Хорошее представление о решении проблем 101 | дает поиск на StackOverflow, где почти 102 | на любую проблему дается большое количество 103 | вариантов решения. Поиск решений и выбор 104 | лучшего - это основная работа Java-разработчика, 105 | и мы максимально постараемся этому научить: 106 | каждый раз в конкретной ситуации вы должны 107 | будете САМИ думать, что применять и как. 108 | Выполняя домашние задания, вы должны приложить 109 | все усилия, чтобы самостоятельно найти решение. 110 | Далее в начале следующего занятия вы также 111 | посмотрите разбор решения, подготовленного 112 | Григорием Кислиным. 113 | 114 | #### 3-й вариант ошибочного представления о стажировке TopJava связан с неверным представлением о том зачем нужна проверка домашних заданий. Например, человек может ошибочно рассуждать так: 115 | 116 | >я хочу проходить стажировку с проверкой ДЗ, 117 | > чтобы мне рассказали, как нужно правильно выполнять задания 118 | 119 | Задача проверки не в том, чтобы общими усилиями 120 | написать код, который ты и так увидишь в разборе. 121 | Если у тебя что-то не получается, наша 122 | задача - не найти ошибку/подебажить за тебя/почитать 123 | логи и т. п., а подсказать способ самостоятельно 124 | найти решение (хотя для этого мы сначала сами 125 | ищем/дебажим/читаем) 126 | Вторая важная задача, которую решает 127 | проверяющий, - увидеть то, что не увидел ты. 128 | Когда ты сдаешь задание на ревью, тебе 129 | может казаться, что все почти идеально. Проверяющий 130 | подскажет тебе, где ты что-то пропустил из-за 131 | недостатка опыта, что позволит тебе улучшить код. 132 | 133 | --- 134 | 135 | >Любое знание стоит воспринимать как подобие семантического дерева: убедитесь в том, что понимаете фундаментальные принципы, то есть ствол и крупные ветки, прежде чем лезть в мелкие листья-детали. Иначе последним не на чем будет держаться 136 | — Илон Маск 137 | 138 | Обычно в занятии дается много дополнительного 139 | материала и ссылок. Не стоит стремиться прочитать 140 | все ссылки урока, их можно использовать как 141 | справочник. Гораздо важнее пройти основной 142 | материал урока и сделать домашнее 143 | задание - этого достаточно для усвоения 144 | материала и получения той самой 145 | основы - ствола и крупных веток, на 146 | которых впоследствии можно наращивать листву. 147 | 148 | 149 | Как правило, подбираются участники разного 150 | уровня. Поэтому главное – не стеснятся 151 | задавать вопросы (после самостоятельного 152 | гугления и поиска решения). Всегда есть 153 | поддержка группы (в том числе от пришедших 154 | на бесплатный повтор участников), моя и ассистентов. 155 | 156 | --- 157 | ### Основные навыки программиста, которые необходимо развить на курсе 158 | Давайте перечислим набор навыков, которые 159 | вам необходимо развивать в ходе курса 160 | и которые необходимы любому программисту: 161 | 162 | - умение и привычка искать 163 | информацию, чтобы иметь больший выбор из 164 | доступных вариантов технологий и подходов 165 | к решению задачи, умение пользоваться StackOverflow; 166 | - умение пользоваться дебаггером в Intellij Idea; 167 | - умение пользоваться DevTools в браузере; 168 | - определенный кругозор и опыт для того, чтобы придумывать поисковые запросы. 169 | -------------------------------------------------------------------------------- /doc/video4.md: -------------------------------------------------------------------------------- 1 | ## Структура приложения (многоуровневая архитектура) 2 | ## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) [Видео](https://drive.google.com/file/d/1UHzSy9i-uonmTMFoR5v69Y-vyWLCLQWd) 3 | 4 | Приложение, которое мы будем разрабатывать, это [программа для подсчета калорий](http://javaops-demo.ru/topjava). 5 | 6 | В этом видео обсудим структуру этого приложения. 7 | 8 | --- 9 | Ссылки на отчеты, которые будут использоваться в этом уроке: 10 | 11 | - [Многоуровневая архитектура (русскоязыная статья в Wikipedia)](https://ru.wikipedia.org/wiki/%D0%9C%D0%BD%D0%BE%D0%B3%D0%BE%D1%83%D1%80%D0%BE%D0%B2%D0%BD%D0%B5%D0%B2%D0%B0%D1%8F_%D0%B0%D1%80%D1%85%D0%B8%D1%82%D0%B5%D0%BA%D1%82%D1%83%D1%80%D0%B0) 12 | - [Multitier architecture (англоязычная статья в Wikipedia)](https://en.wikipedia.org/wiki/Multitier_architecture) 13 | 14 | --- 15 | 16 | 17 | 18 | На структурной схеме приложения вы видите, что оно условно разделено на 4 части: **Views**, 19 | **Controller**, **Service** и **Repository**. 20 | 21 | Такой подход является реализацией многоуровневой архитектуры в программировании. 22 | По-английски этот подход называется **_Multitier architecture_**. 23 | 24 | Его суть заключается в разделении приложения на несколько слоев, 25 | каждый из которых ответственен за конкретную задачу. 26 | 27 | ### Слой отображения (View) 28 | Views соответствует слою отображения (или presentation layer). Это user interface (UI) или 29 | фронтенд - все то, что мы видим и с чем взаимодействуем в браузере. 30 | В качестве View могут быть HTML-страницы, созданные с использованием специальных 31 | движков шаблонов, например, JSP (встроен в Tomcat), или 32 | Thymeleaf (шаблоны по умолчанию в Spring Boot), или отдельное frontend-приложение, 33 | написанное на одном из JavaScript-фреймворков. 34 | 35 | В случае с движками шаблонов HTML-страницы будут располагаться в одном проекте 36 | с основным кодом приложения. Для приложений с "небогатым" UI используются именно шаблоны. 37 | Этот подход отличается от так называемых RIA - rich internet application - приложений со сложным UI. 38 | 39 | Главное отличие rich internet application от приложений с фронтендом 40 | на движках шаблонов заключается в том, что фронтенд, созданный на движке 41 | шаблонов, работает на сервере, и это что-то простое. 42 | В случае с rich internet application фронтенд-приложение загружается 43 | через Интернет к вам на компьютер и запускается в браузере. 44 | Оно может быть максимально сложным и выполнять функции традиционных 45 | десктоп-приложений. 46 | Иногда в одном приложении смешиваются оба способа: например, страница 47 | логина-пароля в RIA делаются на шаблонах. 48 | 49 | Создание простого фронтенда на движке шаблонов проще, поэтому 50 | в курсе мы будем использовать этот способ. 51 | 52 | ### Слой контроллеров (Controller) 53 | Следующий слой, который мы видим - это **Controller**. 54 | 55 | В многоуровневой архитектуре он соответствует слою, который 56 | называется "**_Слой приложения_**" или "**_Application layer_**"). 57 | В GRASP (General Responsibility Assignment Software Patterns) 58 | он так и называется - Controller layer. 59 | 60 | Это слой приложения, который ответственен за обработку HTTP-запросов и проверку корректности входных данных. Если мы открываем главную страницу на сайте или отправляем заполненную на сайте форму, фронтенд-приложение отправляет HTTP-запрос серверу (в нашем случае контейнеру сервлетов), который принимает запрос и перенаправляет его в контроллер, соответствующий введенному в браузере URL или адресу, который вызывается при отправке формы через сайт. 61 | Также контроллеры могут принимать запросы не только от фронтенда, но и от других приложений. 62 | 63 | Слой контроллеров не имеет доступа к базе данных. Контроллеры общаются только с сервисами. 64 | 65 | ### Слой сервисов (Service layer) 66 | Слой **Service** на схеме приложения соответствует слою 67 | бизнес-логики (или **_Business layer_**) в многоуровневой архитектуре. 68 | В слое Service инкапсулирована вся бизнес-логика нашего приложения. 69 | Если коммуникация с фронтендом или другими приложениями - это ответственность контроллеров, 70 | то обработка данных - это ответственность сервисов. 71 | 72 | ### Слой доступа к данным (Data layer) 73 | Слой сервисов общается со слоем, ответственным за работу с базами данных. 74 | Этот слой называют **Data layer** (также можно встретить 75 | названия **Persistence Layer** или **Data access layer**), и он 76 | представлен в виде **_Data Access Object_** классов 77 | (коротко - **_DAO-классы_**) или классов, реализующих паттерн "репозиторий". 78 | С обоими видами классов вы попрактикуетесь в ходе курса. 79 | [Репозиторий - это также один из архитектурных паттернов](https://martinfowler.com/eaaCatalog/repository.html) 80 | 81 | Подобное разделение приложения на слои дает гибкость 82 | и существенно упрощает доработку и переиспользование приложения. 83 | Например, создав по такому принципу приложение, 84 | содержащее слои репозиториев, сервисов и контроллеров, 85 | мы в дальнейшем можем легко использовать это приложение 86 | с различными фронтенд-приложениями или мобильными приложениями. 87 | Если мы решим перейти на другую базу данных, мы можем 88 | переписать только слой репозиториев, и нам не требуется 89 | вносить изменения в слои сервисов и контроллеров. 90 | 91 | >Для маленького приложение такой подход может показаться 92 | >избыточно сложным, но по мере расширения это является спасением. 93 | 94 | Подавляющее большинство реальных приложений построено с использованием именно этой архитектуры. 95 | 96 | ### Краткие итоги 97 | В этом видео мы познакомились с концепцией многоуровневой архитектуры, 98 | которую мы применим при создании приложения на курсе. 99 | Многоуровневая архитектура предполагает разделение приложения на слои: 100 | - Views - слой отображения является фронтендом; 101 | - Controller - слой приложения ответственен за прием и валидацию входных данных; 102 | - слой Service включает в себя весь код, отражающий бизнес логику; 103 | - Repository или Data layer отвечает за взаимодействие с базой данных. 104 | 105 | Также мы обсудили какие преимущества дает такой подход. 106 | Среди преимуществ в первую очередь возможность повторного 107 | использования различных слоев и упрощение их доработки и изменения. 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /doc/video5-vcs-git.md: -------------------------------------------------------------------------------- 1 | ## Системы управления версиями, Git 2 | ## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) [Видео](https://drive.google.com/file/d/1uFjIsxsaSAXxFSwSpjJIGK7Ug2VXf6yH) 3 | 4 | video5-vcs-git.md 5 | 6 | В этом уроке мы рассмотрим системы управления версиями 7 | и самую популярную из них - Git. 8 | 9 | --- 10 | * [StackOverflow 2021 survey](https://insights.stackoverflow.com/survey/2021#technology-most-popular-technologies) 11 | * [Введение в Git и GitHub: установка и настройка](https://topjava.ru/blog/vvedeniye-v-git-github-ustanovka-i-nastroyka) 12 | * [Введение в Git и GitHub: базовые команды](https://topjava.ru/blog/vvedeniye-v-git-github-bazovyye-komandy) 13 | * [Введение в Git и GitHub: ошибки использования](https://topjava.ru/blog/vvedeniye-v-git-oshibki-ispolzovaniya-ch-9) 14 | * [Бесплатная русскоязычная книга Pro Git](https://git-scm.com/book/ru/v2/) 15 | --- 16 | 17 | Git является де-факто стандартом среди систем управления версиями. 18 | Опрос, проведенный StackOverflow в 2021 году показывает, 19 | что Git используют почти 95% опрошенных разработчиков. 20 | 21 | Когда-то популярная централизованная система контроля 22 | версий SVN (Subversion) практически полностью заменена Git. 23 | Но некоторые большие проекты все еще используют SVN. 24 | Примером такого проекта является WordPress. 25 | Я также все еще иногда встречаю SVN в вакансиях российских компаний. 26 | 27 | ### Что такое Git и GitHub 28 | В ходе курса мы будем использовать Git. 29 | Git - это распределенная система управления версиями. 30 | Это означает, что код, над которым работает команда, 31 | и ранее сохраненные (закоммиченные) версии проекта 32 | хранится на компьютерах каждого члена команды, 33 | а также в удаленном репозитории, который можно 34 | сравнить с облачным хранилищем. 35 | 36 | Некоторые путают Git и GitHub, но это не одно и то же. 37 | 38 | **Git** — это утилита, которую 39 | программист устанавливает у себя на компьютере для 40 | сохранения состояний проектов и контроля версий проекта. 41 | 42 | **GitHub** — это провайдер удаленных репозиториев, 43 | сайт (хостинг) для хранения кода проекта и его изменений, 44 | для обмена файлами с членами команды проекта. 45 | Программисты могут создавать на GitHub публичные репозитории, 46 | в которых код доступен всем. Компании могут приобрести платный 47 | аккаунт на GitHub и вести свои проекты в закрытых репозиториях, 48 | доступ к которым имеют только члены команды проекта. 49 | Существуют и другие подобные сайты - провайдеры удаленных 50 | репозиториев, например, BitBucket, SourceForge, GitLab и т. д. 51 | 52 | 53 | ### Как работают Git и GitHub 54 | 55 | 56 | Говоря кратко, работа с Git и удаленным репозиторием 57 | (в нашем случае это Github) выглядит следующим образом. 58 | 59 | Первый разработчик, который начинал работу над проектом, 60 | использовал команду **_git init_** в корневой директории 61 | проекта для того, чтобы инициализировать пустой Git-репозиторий. 62 | В этот момент Git создает в директории с проектом скрытую 63 | директорию, содержащую файлы, необходимые для его работы. 64 | Теперь первый разработчик может с помощью команды **_git add_** 65 | добавлять файлы проекта в индекс - то есть в зону, 66 | отслеживаемую git, а также может фиксировать изменения, 67 | создавая коммиты (**_git commit_**), и загружать их в 68 | удаленный репозиторий (например, на GitHub) с помощью 69 | команды **_git push_**. 70 | 71 | Спустя некоторое время к работе над проектом подключается второй разработчик. 72 | 73 | Поскольку первый разработчик пушил изменения файлов проекта 74 | на удаленный репозиторий, второй разработчик может скачать 75 | их себе на компьютер с помощью команды **_git pull_** 76 | и продолжить работу с учетом этих изменений. 77 | 78 | Давайте повторим. 79 | В описанной работе использовались команды: 80 | 81 | * **_git init_** - эта команда инициализирует работу Git 82 | для конкретного проекта. В папке с проектом создается 83 | скрытая папка, хранящая все файлы, необходимые Git 84 | для работы. Папка с этими файлами впоследствии будет 85 | загружена в удаленный репозиторий, и второй программист, 86 | скачавший проект, увидит у себя на компьютере все ранее 87 | созданные с помощью Git версии. 88 | * **_git add_** - это команда, которая добавляет файлы 89 | проекта в индекс (или отслеживаемую зону), чтобы их можно 90 | было в какой-то момент закоммитить (то есть сохранить, зафиксировать). 91 | * **_git commit_** - сохраняет все файлы проекта в 92 | текущем состоянии так, что мы в любой момент сможем 93 | вернуться к этому состоянию - посмотреть, как изменились 94 | файлы, или даже полностью вернуть проект к состоянию 95 | данного коммита. 96 | * **_git push_** - загружает файлы в удаленный Git-репозиторий, 97 | чтобы их могли скачать другие программисты. 98 | * **_git pull_** используют для того, чтобы скачать 99 | файлы из удаленного репозитория себе на компьютер. 100 | 101 | Также Git позволяет создавать ветки. Это означает, 102 | что вы можете создать копию стабильного кода и 103 | продолжить работу в этой копии, не подвергая риску 104 | стабильную версию. Когда код с новой функциональностью 105 | готов, отлажен и протестирован, он может быть 106 | слит ("смержен", от слова "merge") в основную ветку со стабильным кодом. 107 | 108 | С помощью этих функций Git позволяет команде разработчиков 109 | работать одновременно над разными задачами и поддерживать 110 | код в стабильном состоянии. 111 | 112 | Также Git позволяет в любой момент понять, кто и когда внес 113 | изменения в определенный код, что существенно упрощает взаимодействия 114 | с коллегами. Например, в случае, если вы видите новые 115 | строки кода, которые вызывают у вас вопросы, с помощью 116 | Git вы можете разобраться, кто внес изменения именно 117 | в эти строки, и связаться с этим человеком 118 | для уточнения деталей. 119 | 120 | Если произошла ситуация, при которой два разработчика 121 | изменили один и тот же файл, Git потребует от вас вручную 122 | отрегулировать такой конфликт. 123 | 124 | Также благодаря Git у вас всегда под рукой детальная 125 | история изменений. С помощью комментариев к коммитам 126 | вы можете детально документировать ход работы над 127 | проектом и в случае необходимости разобраться, в 128 | какой момент что-то пошло не так, и откатиться 129 | к той версии, где ошибка еще не была сделана. 130 | Или просто выяснить, как выглядел код определенного 131 | класса или метода в определенной версии и внести правки 132 | в текущую версию, если это необходимо. 133 | 134 | ### Дополнительные материалы 135 | 136 | Для изучения Git рекомендуем в первую очередь ознакомиться со статьями на сайте [topjava.ru](https://topjava.ru): 137 | 138 | * [Введение в Git и GitHub: установка и настройка](https://topjava.ru/blog/vvedeniye-v-git-github-ustanovka-i-nastroyka) 139 | * [Введение в Git и GitHub: базовые команды](https://topjava.ru/blog/vvedeniye-v-git-github-bazovyye-komandy) 140 | * [Введение в Git и GitHub: ошибки использования](https://topjava.ru/blog/vvedeniye-v-git-oshibki-ispolzovaniya-ch-9) 141 | 142 | В них дается детальная инструкция по первоначальной настройке 143 | Git, GitHub, в том числе инструкция по настройке 144 | Access token в GitHub, что вам обязательно нужно будет сделать. 145 | 146 | Также можно упомянуть официальную русскоязычную книгу Pro Git, 147 | которая доступна [бесплатно в электронном виде](https://git-scm.com/book/ru/v2/). 148 | 149 | ### Как мы будем использовать Git на курсе 150 | В Git очень много команд, но в ходе курса мы будем использовать 151 | только самые необходимые из них. 152 | С git можно работать как через терминал с помощью команд, 153 | так и с помощью различных программ с графическим интерфейсом. 154 | Мы будем преимущественно использовать интеграцию 155 | IntelliJ Idea с Git, поскольку она очень удобна 156 | и существенно упрощает работу. 157 | Однако знать, как выполнять аналогичные операции 158 | в терминале, очень полезно. 159 | 160 | ### Резюме 161 | В этом уроке мы сделали краткий обзор систем управления 162 | версиями и самой популярной из них - Git: 163 | 164 | * разобрались в различиях Git и GitHub. 165 | Git - это система контроля версий, а 166 | GitHub - провайдер удаленных репозиториев, один из многих, доступных на рынке. 167 | * кратко познакомились с тем, как Git работает. 168 | Узнали о командах git init, git add, git commit, git push и git pull. 169 | * Также мы обсудили, что такое ветки и какие возможности они дают. 170 | 171 | --- 172 | 173 | Если вы не работали раньше с Git, не беспокойтесь. 174 | В последующих уроках работа с Git будет изучаться 175 | на практике в ходе работы над проектом. Но дополнительно 176 | почитать о Git все же стоит. 177 | 178 | 179 | 180 | 181 | -------------------------------------------------------------------------------- /graduation.md: -------------------------------------------------------------------------------- 1 | ## Выпускной проект [стажировки TopJava](https://javaops.ru/view/topjava) 2 | 3 | Design and implement a REST API using Spring-Boot/Spring Data JPA **without frontend**. 4 | 5 | The task is: 6 | 7 | Build a voting system for deciding where to have lunch. 8 | 9 | * 2 types of users: admin and regular users 10 | * Admin can input a restaurant and it's lunch menu of the day (2-5 items usually, just a dish name and price) 11 | * Menu changes each day (admins do the updates) 12 | * Users can vote for a restaurant they want to have lunch at today 13 | * Only one vote counted per user 14 | * If user votes again the same day: 15 | - If it is before 11:00 we assume that he changed his mind. 16 | - If it is after 11:00 then it is too late, vote can't be changed 17 | 18 | Each restaurant provides a new menu each day. 19 | 20 | As a result, provide a link to github repository. It should contain the code, README.md with API documentation and couple curl commands to test it (**better - link to Swagger**). 21 | 22 | ----------------------------- 23 | P.S.: Make sure everything works with latest version that is on github :) 24 | P.P.S.: Assume that your API will be used by a frontend developer to build frontend on top of that. 25 | 26 | ----------------------------- 27 | 28 | ## ![error](https://cloud.githubusercontent.com/assets/13649199/13672935/ef09ec1e-e6e7-11e5-9f79-d1641c05cbe6.png) Рекомендации 29 | 30 | **Пишем выпускной проект как тестовое задание на работу** 31 | 32 | - **Не изобретай велосипедов!** Грубая ошибка - пытаться сделать стандартные вещи по-своему, чаще всего криво. На проекте все должно быть единообразно! Ваш проект TopJava - сделай все МАКСИМАЛЬНО в этом 33 | стиле. Если тебе кажется, что есть лучшее решение, чем в TopJava - пишите мне в личку, я всегда открыт для улучшений. 34 | - **Рекомендую писать проект на востребованном на рынке стеке**: Spring Boot + Spring Data JPA (работа с БД) + Swagger/OpenAPI 3.0 (REST документация). 35 | - **Оптимально подойдет код миграции TopJava на Spring Boot в конце стажировки или [курса BootJava](https://javaops.ru/view/bootjava)** 36 | 37 | *Представьте себе, что ПМ (лид, архитектор) дал вам ТЗ и некоторое время недоступен. У вас, конечно, есть много мыслей, для чего нужно приложение, как исправить ТЗ, дополнить его и сделать правильно. 38 | НО НЕ НАДО ИХ РЕАЛИЗОВЫВАТЬ В КОДЕ. Нужно сделать все строго по ТЗ, максимально просто, удобно для доработок и для использования со стороны клиента.* 39 | 40 | > Совершенство достигнуто не тогда, когда нечего добавить, а тогда, когда нечего отнять 41 | 42 | _Антуан де Сент-Экзюпери_ 43 | 44 | ### 1: ТЗ (Тех.задание) 45 | 46 | - 1.1: Читай ТЗ ОЧЕНЬ внимательно, НЕ надо ничего своего туда домысливать и творчески изменять 47 | - 1.2: Учитывай, что пользователей может быть ОООЧЕНЬ много, а админов - МАЛО 48 | - 1.3: Сначала сделай основные сценарии по ТЗ. Все остальное (если очень хочется, 3 раза подумай) - потом. 49 | 50 | ### 2. API 51 | 52 | - 2.1: API продумывай с точки зрения не программиста и объектов, а с точки зрения того, кто им будет пользоваться (клиента, UI) 53 | - 2.1: Тщательно считайте количество запросов в вашем API для отображения нужной информации 54 | - 2.3: Из потребностей приложения (клиента) реализуй только очевидные сценарии. Необходимо и достаточно: ВСЕ НЕОБХОДИМОЕ для клиента и НИЧЕГО ЛИШНЕГО. Процесс творческий, приходит с опытом. 55 | - 2.4: Делаем REST API в соответствии с концепцией REST (url в общем имеют вид`{ресурс}/{id_ресурсa}[/{подресурс}/{id_подресурсa}][параметры]`, см. ниже ссылки про REST и иерархию). Имена ресурсов во множественном числе! 56 | Самая распространенная и грубая ошибка - не придерживаться этих простых правил. 57 | - **[15 тривиальных фактов о правильной работе с протоколом HTTP](https://habrahabr.ru/company/yandex/blog/265569/)** 58 | - **[10 Best Practices for Better RESTful API](https://medium.com/@mwaysolutions/10-best-practices-for-better-restful-api-cbe81b06f291)** 59 | - **[REST resource hierarchy](https://stackoverflow.com/questions/20951419/what-are-best-practices-for-rest-nested-resources)** 60 | - [Лучшие практики разработки REST API: правила 1-7,15-17](https://tproger.ru/translations/luchshie-praktiki-razrabotki-rest-api-20-sovetov/) 61 | - 2.5: Разделение на роли я предпочитаю на уровне URL. Сразу и однозначно видно, какой API у админа, какое у пользователя (API админа начинается, например, с */admin/...*). 62 | - 2.6: На управление (CRUD) ресторанами и едой должны быть ОТДЕЛЬНЫЕ контроллеры. Не надо все, что может админ, сваливать в одну кучу! Смотрите на результат операции - помещаете в этот контроллер! 63 | - 2.7: Проверьте в Swagger, что в POST и PUT нет ничего лишнего, а в GET есть все необходимые данные. Например, при запросе голоса должен в ответе отображаться `id` ресторана, а не весь объект, при создании-редактировании ресторана в примерах swagger не должно быть меню и еды. 64 | - 2.8: `Profile` означает, что данные принадлежат профилю пользователя. Все остальное называйте по-другому. 65 | - 2.9: Отсутствие данных часто бывает "бизнес кейсом", те НЕ ошибкой в запросе или приложении. Исключение - это ошибка, например неверный `id`. Запрос на данные, которые могут быть, могут нет, не должен приводить к исключениям. Посмотрите в сторону `ResponseEntity.of()` 66 | - 2.10: По REST URL должно быть однозначно понятно, какие будут параметры на входе и что ждать на выходе. Без сюрпризов! 67 | 68 | ### 3: Код: 69 | - 3.1: Строго соблюдайте соглашения Java по именованию: пакеты ТОЛЬКО маленькими буквами, методы начинаются с маленькой буквы, классы с большой. Незнания Java Core - тестовое задание сразу в корзину. 70 | - 3.2 В проекте (и тестовом задании на работу), в отличие от нашего учебного topjava, оставляйте только необходимый для работы по ТЗ приложения код, ничего лишнего 71 | - 3.2.1: НЕ надо делать разные профили базы и работы с ней 72 | - 3.2.2: НЕ надо делать абстрактных контроллеров на всякий случай 73 | - 3.2.3: НЕ надо делать сервисов, если там нет ничего, кроме делегирования 74 | - 3.2.4: НЕ нужны локализация, UI, типы ошибок, Json View 75 | - 3.3: Название пакетов, имен классов для `model/to/web` стандартные (например `model/domain`). НЕ надо придумывать своих собственных правил 76 | - 3.4: Проверьте, не торчат ли из кода учебные уши TopJava, типа `ProfileRestController.testUTF()`, `AbstractServiceTest.printResult()` или закомментированные `JdbcTemplate`. Назначение выпускного 77 | совсем другое 78 | - 3.5: Вместо `return ResponseEntity.ok(object)` в контроллерах пишите `return object`. Проще! 79 | 80 | ### 4: Модель 81 | 82 | - 4.1: В БД обычно хранятся все введенные пользователем и админом данные c возможность их редактирования. Это означает, что мы не удаляем прошлые меню, а храним их в базе, как и историю голосования. Есть базовые вещи, которые закладываются в архитектуру приложения, и есть неочевидные доработки к ТЗ, делать не надо. 83 | - 4.2: Не делайте в модели объектов, которые не будут использоваться в коде (например, не надо двунаправленных связей, если достаточно однонаправленных) 84 | - 4.3: еще раз про [hashCode/equals в Entity](https://stackoverflow.com/questions/5031614/the-jpa-hashcode-equals-dilemma): не делайте в модели сравнение по полям! 85 | - 4.4: ORM работает с объектами. [Иногда, для упрощения логики, fk_id как поля допустимы](https://stackoverflow.com/questions/6311776/hibernate-foreign-keys-instead-of-entities) 86 | 87 | ### 5: Архитектура / pom 88 | - 5.1: Можно: 89 | - или подключить DATA-REST (см.курс [Spring Boot 2.x + HATEOAS](https://javaops.ru/view/bootjava)). Контроллеры генерируются автоматически по репозиториям, требуется настройка ресурсов в кастомных контроллерах 90 | - **РЕКОМЕНДУЕТСЯ** делать на основе миграции TopJava / кода [курса BootJava](https://javaops.ru/view/bootjava) 91 | 92 | Нельзя смешивать эти подходы вместе! Я рекомендую 2-й вариант, без data-rest. Обязательно посмотрите в Swagger, какие контроллеры получились в результате. 93 | - 5.2: Не размещайте бизнес-логику приложения и преобразования в TO в слое доступа к DB 94 | - 5.3: Не смешивайте TO и Entity вместе. Они должны быть независимыми друг от друга. На TopJava мы смотрели разные варианты [c использованием TO и без](https://stackoverflow.com/a/21569720/548473). 95 | Делаем максимально просто. 96 | - 5.4: [Use for money in java app](http://stackoverflow.com/a/43051227/548473) 97 | - 5.5 Не надо явно указывать версии зависимостей в `pom`, если они наследуются от `spring-boot-starter-parent` 98 | 99 | ### 6: Доступ к БД 100 | 101 | - 6.1: Используйте Spring Data JPA (без лишней делегации). Методы Repository можно вызывать напрямую из сервиса или из контроллера. 102 | - 6.2: В DATA-JPA 2.x используются `Optional`. Попробуйте работать с ними, это безопасный способ работать с null-значениями (используйте `orElseThrow`) 103 | - 6.3: Не делайте при обновлении записи ради экономии пары строчек кода так: 104 | ``` 105 | if(updateCondition) 106 | repository.delete(entity) 107 | } 108 | repository.save(entity) 109 | ``` 110 | Обновление записи базы должно быть через `UPDATE`. 111 | 112 | ### 7: База Данных 113 | 114 | - 7.1: Берите без установки (H2 или HSQLDB). Одну и **в памяти**! Ваше приложение должно сразу запуститься, без всяких настроек и переменных окружения 115 | - 7.2: Тщательно считайте количество обращений в базу на каждый запрос. Особенно при запросах от юзеров, которых очень много! Также на сложность запросов от них, чтобы не положить базу 116 | - 7.3: Сделайте [индексы к таблицам](https://ru.wikipedia.org/wiki/Индекс_(базы_данных)). Попробуйте обеспечить UNIQUE (один голос пользователя в день, один уникальный пункт меню в день). 117 | Следите за **порядком полей в индексе**, от этого зависит индексирование запросов. 118 | - 7.4: При популировании добавь записи за сегодняшний день - `now()`, чтобы всегда были актуальные исходные данные 119 | - 7.5: Поля базы case insensitive, не пишите camelStyle (для которых нужны кавычки) 120 | - 7.6: Таблицы обычно именуются в единственном числе. Исключение - `users`, `orders` и другие зарезервированные слова 121 | - 7.7: `date`/`timestamp` - зарезервированное слово, лучше избегать их при именовании полей 122 | 123 | ### 8: Security 124 | 125 | - 8.1: Проверьте, станет ли код проще с `@AuthenticationPrincipal` (урок 11, доступ к AuthorizedUser). 126 | - 8.2: Я предпочитаю четкое разделение ролей на основе URL. Для админа URL содержит `/admin` 127 | - 8.3: Еще раз - призываю не менять код TopJava 128 | 129 | ### 9: Кэширование 130 | 131 | - 9.1: Кэширование желательно для частых и редко меняющихся запросов от пользователей. 132 | Тщательно продумайте, что надо кэшировать (самые частые запросы), а что нет (большие или редко запрашиваемые данные) 133 | - 9.2: Проверьте соответствие ключей к кэшу (параметры кэшируемого метода) с конфигурацией (например в singleNonExpiryCache, heap=1 в кэше может содержаться только ОДНО значение). 134 | 135 | ### 10: Валидация 136 | 137 | - 10.1: Одних аннотаций валидации на полях недостаточно. Должны быть `@Valid/@Validation` в контроллере 138 | - 10.2: Прячте `id` при `create/update` в примерах Swagger. Если их передали - проверяйте на соответствие (в TopJava это `ValidationUtil.checkNew()/assureIdConsistent()`) 139 | 140 | ### 11: Дополнительно 141 | 142 | - 11.1: По возможности сделать JUnit-тесты. Можно не делать 100% покрытие, только основные сценарии 143 | - 11.2: Уделяйте внимание обработке ошибок. 144 | 145 | ### 12: `readme.md`: 146 | 147 | - 12.1: Поместите вначале `readme` ТЗ или **ссылку на него** - будет понятно о чем твой проект 148 | - 12.2: Если задание на English, описание пиши также на English (то же самое относится к языку резюме: вакансия на English предполагает резюме на English) 149 | - 12.3: Требуемые примеры `curl` не прячьте, а пишите здесь! Оптимально сделать **ссылку на `Swagger UI` с креденшелами для выполнения запросов** 150 | - 12.4: Проверяют люди с опытом в Java: не надо писать инструкций, как устанавливать Java и Maven 151 | 152 | ### 13: Git 153 | 154 | - 13.1: Должна быть история ваших комитов с внятными комментариями. Это смотрят. 155 | > Эйчар обращает внимание на дату создания аккаунта и то, как в него заливались коммиты (элементы проекта), постепенно или в один день, насколько технологии в аккаунте коррелируют с технологиями в резюме 156 | - 13.2: Не комить служенбые файлы: логи, DB, настройки IDEA и пр., это сразу - уровень Junior. 157 | - 13.3: Все служебные файлы должны быть в `.gitignore` 158 | 159 | ## Проверка 160 | 161 | - Попробуй подергать свое API по всем типичным сценариям ТЗ! 162 | - Удобно использовать? Можно сделать проще? Например, чтобы проголосовать за ресторан залогиненному юзеру, достаточно `restorauntId`. 163 | - Сколько раз пришлось его вызвать API для типичного сценария (например посмотреть рестораны с едой на сегодня)? 164 | - Сколько запросов к базе было сделано? Можно ли сократить (например с `FETCH/Graph` или через кэширование)? 165 | - **Еще раз - проверь все запросы в Sawgger, смотри на формат запросов и данные в ответе. Все должно работать, есть все данные и нет ничего лишнего** 166 | - 13.2: API ДОЛЖЕН соответствовать принципам REST (см. ссылки выше) 167 | - 13.3: ОБЯЗАТЕЛЬНО: запустите `mvn test` - ошибок быть не должно 168 | - 13.4: ОБЯЗАТЕЛЬНО: запустите приложение без всяких предварительных настроек (базы, переменных окружения, ..), лучше на другом компьютере. Приложение должно запускаться и работать! 169 | 170 | ## Оценка 171 | ТЗ очень скромное, не дает понимания, что хочет получить заказчик, именно поэтому моих комментариев к этому ТЗ больше на 2 порядка. Это реальное тестовое задание на работу. При оценке учитывается отсутствие грубых ляпов, простота и красота решения + его расширяемость, если понадобится дорабатывать приложение. Если практический опыт небольшой, еще раз очень рекомендую держаться как можно ближе к нашему коду на Spring Boot. 172 | Тестовое задание дается для того, чтобы оценить вас, как программиста. Нужны ли вы компании или нет. Это умение спроектировать грамотную модель и API, придерживаясь принципов REST и без своих велосипедов, и ваш чистый красивый код. 173 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | ru.javawebinar 6 | topjava 7 | jar 8 | 9 | 1.0-SNAPSHOT 10 | 11 | Calories Management 12 | https://javaops-demo.ru/topjava 13 | 14 | 15 | 1.8 16 | UTF-8 17 | UTF-8 18 | 19 | 20 | 21 | topjava 22 | install 23 | 24 | 25 | org.apache.maven.plugins 26 | maven-compiler-plugin 27 | 3.14.0 28 | 29 | ${java.version} 30 | ${java.version} 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/main/java/ru/javawebinar/topjava/Main.java: -------------------------------------------------------------------------------- 1 | package ru.javawebinar.topjava; 2 | 3 | /** 4 | * @see Demo application 5 | * @see Initial project 6 | */ 7 | public class Main { 8 | public static void main(String[] args) { 9 | System.out.format("Hello TopJava Enterprise!"); 10 | } 11 | } 12 | --------------------------------------------------------------------------------