Онлайн-проект Topjava
- Не стоит стремиться прочитать все ссылки урока, их можно использовать как справочник. Гораздо важнее пройти основной материал урока и сделать Домашнее Задание
- Обязательно посмотри правила работы с патчами на проекте
- Делать Apply Patch лучше по одному, непосредственно перед видео на эту тему, а при просмотре видео сразу отслеживать все изменения кода проекта по изменению в патче (
Git-> Local Changes-> Ctrl+D) - При первом Apply удобнее выбрать имя локального ченджлиста Name: Default. Далее все остальные патчи также будут в него попадать.
- Код проекта обновляется и не всегда совпадает с видео (можно увидеть как развивался проект). Изменения в проекте указываю после соответствующего патча.
Материалы занятия (скачать все патчи можно через Download/Скачать папки patch)
- переименовал классы
UserMeal*в более красивыеMeal* - преименовал
MealWithExceedtransfer object класс (что это такое пройдем позже) вMealTo(data transfer object naming convention)
- В патче
prepare_to_HW0.patchвступительного задания метод фильтрации вTimeUtilпереименовали вisBetweenHalfOpen(также изменилась логика сравнения -startTimeвключается в интервал)
ВНИМАНИЕ! Патчей 1_opt_2_cycles_HW0 и 1_opt_3_opt2_HW0 не будет в проекте! Делаем в отдельной ветке (у меня MealsUtil_opt). Это варианты решений, которые не идут в master
почему не использовать в
TimeUtilметодыisBefore/isAfter?
это строгие (excluded) сравнения, а нам также нужно краевые значения
В
MealsUtilу нас где-то есть ключевое словоfinal, где-то нет. В чем разница?
Я участвовал в одном проекте, где final был обязательным (в сеттингах IDEA галочка стояла). Но это скорее исключение, чем правило в проектах java (в Java 8 вообще ввели эффективный final, те по факту). Во всех новомодных языках переменные final по умолчанию, а в java нужно помнить и везде добавлять, утомительно. Но если приучитесь - хуже не будет. Я обычно ставлю там, где важно по смыслу (если не забываю).
- DevEcosystem from JetBrains
- Дополнительно:
- 2020 Java Technology Report
- Обзор популярности инструментов и технологий Java за 2016 г.
- Обзор популярности инструментов и технологий Java за 2014 г.
- Видео "Приложение Spring Pet Clinic"
- Приложение Spring Pet Clinic.
- Tiobe index
- RebelLabs Developer Productivity Report 2017: Why do you use the Java tools you use
- The State of Java in 2018
- 2018 JDK, Tools, Platform and Application, processes and you reports
6. Maven.
- Среда сборки проектов Maven.
- The Central Repository
- The Reactor. Snapshots
- Недостатки Maven. Другие инструменты сборки.
- Справочник:
- Обновил зависимость до Servlet 4.0. Установите себе Tomcat 9.x
- Устанавливать Tomcat лучше простым скачиванием архива
xxx.zip(например для Windowsapache-tomcat-9.0.35-windows-x64.zip) и копированием из него в каталог без пробелов и русских букв (примерС:\java\apache-tomcat-9.0.35)
- Обновил сервлеты до версии 4.0 (Tomcat 9 использует это API, хотя для нас не принципиально, т.к. мы никакие фичи 3.x и 4.x Servlet API не используем)
- Переименовал
userList.jspвusers.jsp
- Если зависимость
servlet-apiне подтянулась, сделайReimport All Maven Projects(см. Обновить зависимости в maven проекте). Все зависимости в Maven прект подтягиваются ТОЛЬКО через Maven.- Проверка, кто занял порт (в случае проблем с запуском и дебагом на портах 8080, 8000)
- Деплой war в Tomcat с Application context
- Динамическое обновление без передеплоя
- Tomcat Home Page
- Сервлеты
- Руководство: как создать servlet
- Томкат менеджер: http://localhost:8080/manager
- в
TOMCAT_HOME\conf\tomcat-users.xmlнужно добавить
- в
<user username="tomcat" password="tomcat" roles="tomcat,manager-gui,admin-gui"/>
-
Если проблема с Tomcat debug и работает Dr.Web- нужно его отключить, либо добавить в исключения путь к
.IntelliJIdeaXXX/ -
Наше приложение: http://localhost:8080/topjava
-
Наш сервлет: http://localhost:8080/topjava/users
-
Дополнительно:
- Remote debug встречается много реже - приконнекчивание к уже запущенной JVM, которую, например, нельзя запустить из IDEA. Можно попробовать запустить catalina через
jpda start, задеплоить туда war и уже после этого после приконнектиться через запускTomcat Server -> Remote - HTTP
- Отладчик IntelliJ IDEA
- Yakov Fain: Intro to Java EE. Glassfish. Servlets (по-русски)
- Yakov Fain: HTTP Sessions, Cookies, WAR deployments, JSP (по-русски)
- Golovach Courses: Junior.February2014.Servlets
- Java Server Page
- Java объекты, доступные в JSP
- Remote debug встречается много реже - приконнекчивание к уже запущенной JVM, которую, например, нельзя запустить из IDEA. Можно попробовать запустить catalina через
8. Логирование.
Установите переменную окружения на TOPJAVA_ROOT на корень проекта и перезапустите IDEA. Слеши в пути должны быть в стиле unix (/)
- Set environment for Win/Mac/Unix
- Set environment for UNIX
- Или простой вариант (не забудте добавить и в Run, и в Debug)
- изменения в проекте: убрал
LoggerWrapperи логирую напрямую в логгер SLF4J. При логгировании через вспомогательный класс, в логе теряется имя исходного класса.- удалил зависимость
jul-to-slf4j. Она нам не нужна и, согласно видео Владимира Красильщика про логирование, она замедляет работу- удалил зависимость
jcl-over-slf4j. Используем Spring 5, который напрямую используетslf4jбезcommon-logging. Про миграцию на Spring 5 будет видео в следующих занятиях.- Не делать конкатенацию строк при логгировании сообщений, если уровень логирования в конфигурации выставлен выше уровня логирования в коде
- Java Logging: история кошмара
- JavaRush: Logger
- Ведение лога приложения
- Log4j, Logback
- Добавление зависимостей логирования в проект.
- Logback variable substitution
- Что нужно изменить в
pom.xml, чтобы перейти с logback на log4j ?
Почему
private static final Logger logа неLOG?
Это правило именования констант, которые не "deeply immutable", те если их содержимое можно изменить.
Используются ли еще где-то в реальной разработке JSP, или это уже устаревшая технология? Заменит ли ее JSF (https://javatalks.ru/topics/38037)?
JSF и JSP- разные ниши и задачи. JSP- шаблонизатор, JSF - МVС фреймворк. Из моего опыта- с JSP сталкивался в 60% проектов. Его прямая замена: http://www.thymeleaf.org (в Spring-Boot по умолчанию), но в уже запущенных проектах встречается достаточно редко. JSP не умирает, потому что просто и дешево. Кроме того включается в большинство веб-контейнеров (в Tomcat его реализация Jasper)
JSF- sun-овский еще фреймворк, с которым я ни разу не сталкивался и особого желания нет. Вот он как раз, по моему мнению, активно замещается хотя бы javascript фреймворками (angular, react, vue.js).
А зачем мы использовали logback? Почему SLF4J нас не устроило? Почему реализация логирования не log4j?
SLF4J-API это API. Там есть только пустая реализация org.slf4j.helpers.NOPLogger (можно посмотреть в исходниках). Logback для новых проектов стал стандарт. spring-petclinic и spring-boot используют его по умолчанию.
Откуда на maven диаграмме зависимостей появляется
slf4j-api1.7.25?
Это транзитивная зависимость logback-classic (те подтягивается вместе с ним). Ме ее явно перекрыли новой версией slf4j-api 1.7.30, которая совместима с logback-classic 1.2.3. Можно было бы оставить как есть, но когда мы добавим в проект бриджи, они будут у нас более новые (также с версией 1.7.30).
ОСНОВНОЕ, чему мы учимся на проекте: мыслить и работать как Java разработчики уже сейчас, потом это будет гораздо сложнее и стоить дороже.
Вот на мой взгляд хорошие советы новичкам. От себя я добавлю:
- Учись грамотно формулировать проблему. Проблема "у меня не работает" может иметь тысячи причин. В процессе формулирования очень часто приходит ее решение.
- что я делаю (подробно, чтобы понял человек, который не копался в этом совсем)
- что получаю (обычно верх самого последнего эксепшена)
- мои попытки решения проблемы
- Учись исследовать проблему. Внимательное чтение логов и умение дебажить - основные навыки разработчика. Обычно самый верх самого нижнего эксепшена- причина ошибки, туда нужно ставить брекпойнт.
- Грамотно уделяй время каждой проблеме. Две крайности - сразу бросаться за помощью и биться над ней часами. Пробуй решить ее сам и в зависимости от проблемы выделяй на это разумное время.
Деплоиться в Tomcat лучше как
war exploded: нет упаковки в war и при нажатой кнопкеUpdate Resources on Frame Deactivationможно обновляться css, html, jsp без передеплоя. При измененииweb.xml, добавлении методов, классов необходим redeploy.
- 1.1 По аналогии с
UserServletдобавитьMealServletиmeals.jsp- Задеплоить приложение (war) в Tomcat c
applicationContext=topjava(приложение должно быть доступно по http://localhost:8080/topjava) - Попробовать разные деплои в Tomcat, remote и local debug
- Задеплоить приложение (war) в Tomcat c
- 1.2 Сделать отображения списка еды в JSP, цвет записи в таблице зависит от параметра
excess(красный/зеленый).- 1.2.1 Список еды захардкодить (те проинициализировать в коде, желательно чтобы в проекте инициализация была только в одном месте). Превышение калорий также сделать в коде константой
- 1.2.2 Время выводить без 'T'
- 1.2.3 Список выводим БЕЗ фильтрации по
startTime/endTime - 1.2.4 С обработкой исключений пока можно не заморачиваться, мы будем красиво обрабатывать в конце стажировки
- 1.2.5 Вариант реализации:
- из сервлета преобразуете еду в
List<MealTo>; - кладете список в запрос (
request.setAttribute); - делаете
forwardна jsp для отрисовки таблицы (приredirectатрибуты теряются). - в
JSPдля цикла можно использоватьJSTL tag forEach. Для подключенияJSTLвpom.xmlи шапку JSP нужно добавить:
- из сервлета преобразуете еду в
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
...
- Интернет-приложения на JAVA
- JSP
- Как создать Servlet? Полное руководство
- JSTL для написания JSP страниц
- JSTL: Шаблоны для разработки веб-приложений в java
- JSTL LocalDateTime format
Пример: Simple CRUD using Servlet/JSP
- Пример нужно САМОСТОЯТЕЛЬНО переделать: вместо хранения в MySql нужно хранить в ПАМЯТИ (задание упрощается).
- Классы: сервлет, инрерфейс хранения, его реализация для хранения в памяти
- 2.1 Хранение в памяти будет одна из наших CRUD реализаций (позже будет JDBC, JPA и DATA-JPA).
- 2.2 Работать с реализацией CRUD через интерфейс, который не должен ничего знать о деталях реализации (Map, DB или что-то еще).
- 2.3 Добавить поле
idвMeal/ MealToи реализовать генерацию счетчика, УЧЕСТЬ МНОГОПОТОЧНОСТЬ СЕРВЛЕТОВ - 2.4 Сделать форму редактирования в JSP: AJAX/JavaScript использовать НЕ надо, делаем через
<form method="post">иdoPost()в сервлете. - 2.5 Для ввода дат и времени можно использовать html5 типы, хотя они поддерживаются не всеми браузерами (протестировать свой браузер). В конце курса мы добавим DateTimePicker jQuery plugin, который будет работать на всех браузерах.
- 2.6 Форму на create-update предлагаю не дублировать, сделать одну (хотя это не ошибка сделать разные).
После выполнения ДЗ обязательно проверьте решение на ошибки
Не попадаю на страничку/брекпойнт в сервлете.
- внимательно проверь url и applicationContext (Application Context должен быть тот же, что и url приложения: wiki IDEA)
- посмотрите в task manager: возможно запущено несколько JVM и они мешают друг другу. Лишние java приложения убить.
Приложение не видит TOPJAVA_ROOT.
После выставления переменной окружения IDEA нужно рестартовать. Слеши в пути должны быть в стиле unix (/). Проверить, видит ли java переменную окружения можно так: System.getenv("TOPJAVA_ROOT"). Еще вариант: добавить -DTOPJAVA_ROOT=... в опции запуска приложения, тогда она доступна из java как System.getProperty("TOPJAVA_ROOT").
Проблемы с кодировкой в POST (кракозябры).
Возможное решение - выставьте кодировку ДО первого чтения из request:
protected void doPost(HttpServletRequest request, ...) {
request.setCharacterEncoding("UTF-8");
Если сервлет тыкают несколько пользователей / несколько браузеров, какого должно быть поведение? Нужно ли что-то делать с сессиями?
В Optional нужно делать реализацию хранения многопоточной. Cессии пока не используем (начнутся, когда будет прикручивать авторизацию).
Для чего нам нужна многопоточная реализация коллекции, если каждый пользователь видит только себя?
Реализация хранения в памяти у нас одна на всех. Те коллекция шарится между пользователями, а они в разных потоках ее дергают. Если несколько потоков одновременно будут изменять коллекцию без учета многопоточности (например один будет удалять, второй вставлять), мы получим ConcurrentModificationException
Предпочтительнее ли создавать новый объект
Mealпри каждом update?
Если при обновлении не создавать копию, то сохраненный в памяти объект может кто-то попортить. Вопрос скорее доверия к коду- если проект большой и людей над ним трудится много, то вероятнее нужно копировать.
Почему теряются атрибуты при передаче на сервлет:
http://localhost:8080/topjava/meals?action=add&...иreq.getAttribute("action")= null ?
См. Difference between getAttribute() and getParameter(). Отсюда также следует, что при редиректе атрибуты теряются.
Зачем нужен в jsp
<jsp:useBean id=".." scope="request" type=".."/>?
jsp:useBean нужен IDEA для автодополнений - она понимает тип переменной, которая уже доступна в JSP (например через setAttribute). И еще эта переменная становится доступной в java вставках. Для вывода в JSP это тэг не обязателен. Если тип переменной JSP не совпадает с тем, что в jsp:useBean, будет ошибка.
Мы создали CRUD веб-приложение для управления едой (создание-чтение-обновление-удаление) с использованием сервлетов и логированием. Пока в памяти, и пока еда никому не принадлежит. Пример выполнения ДЗ (не надо сложного интерфейса, Bootstrap css будем проходить на 8-м занятии):
- 0 Обязательно и как можно чаще пользуйтесь Ctrl+Alt+L - отформатировать код класса
- 1 Если в названии класса есть
Meal, не нужно использовать слово meal в методах класса. - 2 Привыкайте писать комментарии к чекину: одной фразой что вы сделали в нем. Например: Meals CRUD implementation. См. Как писать сообщения коммитов
- 3 Хранение в памяти и операции с ней должны выполняться просто и эффективно
- 4 Хранить нужно
Mealи конвертировать ее вMealToкогда отдаем список на отображение в JSP.- excess нужно пересчитывать каждый раз перед отображением
- форматирование должно находится в JSP! Именно он заведует отображением. Повторяем паттерн MVC
- 5 Стили
colorможно применять ко всей строке таблицыtr, а не каждой ячейке. - 6
DateTimeFormatterможно сделать один заранее (он потокобезопасный в отличие отSimpleDateFormatter), а не создавать новый при каждом запросе. - 7 Работать с CRUD надо через интерфейс.
- 8 Реализаций хранения будет несколько, нужно учитывать это в названии класса имплементации работы в памяти.
- 9 В
web.xmlпринято группировать сервлет со своим маппингом - 10 Не размещайте никакую логику (форматирование, счетчики) в бинах, где хранятся только данные (
Meal, MealTo) - 11 Еще раз: детали реализации в памяти не должны быть никому видны. Те НЕ НАДО счетчик размещать в
MealилиMealServletилиMealsUtil, в базе же он будет по другому генерится. - 12
volatileпри ++ не помогает от многопоточности. Почему? - 13 Обратите также внимание на то, чтобы реализация вашей коллекции для хранения еды была также многопоточной.
- 14 Не делайте дублирование кода
MealsUtil. Возможно вам пригодятся константыLocalTime.MINиLocalTime.MAX - 15 Не дублируйте строки в
jsp. Посмотрите на тернарный оператор. - 16 После операции
deleteв браузере должен быть urlhttp:\\localhost:8080\topjava\meals - 17 Перед чекином проверяйте свой ченджлист (
Ctrl+Dна файле изLocal Changes- посмотреть что поменялось). Если там только пробелы/переводы строк, не надо его комитить - делайте файлуGit->revert. - 18 Учтите в названии реализации CRUD, что
- 18.1 у нас будет несколько реализаций (не только в памяти)
- 18.2 у нас будет 2 CRUD (для еды и пользователей). А в реальном проекте их намного больше.
- 19 Сессии НЕ использовать! При редиректе все атрибуты (
req.getAttribute()) теряются (см. вопрос выше). Сценарий редиректа:- 1 из сервлета делаем редирект (снова на сервлет, не на JSP!)
- 2 снова заходим в сервлет
- 3 кладем нужные атрибуты и делаем forward на jsp
- 4 если очень хочется передать параметры из 1. в 2. можно сделать их через параметры запроса (например
meals?id=5) и доставать черезreg.getParameter(id). В моей реализации такого не потребовалось.







