Visitar URL original
topjava/lesson03.md at master · duken1111/topjava · GitHub
Skip to content

Latest commit

 

History

History
226 lines (158 loc) · 23.2 KB

lesson03.md

File metadata and controls

226 lines (158 loc) · 23.2 KB

Онлайн проект Topjava

Коррекция:

добавил setenv.sh и @Override, пофиксил имя DATE_TIME_FORMATTER

  • Apply 0-correction.patch

hw Разбор домашнего задания HW2

video 1. HW2

Изменения в проекте:

  • В репозиториях по другому инстанциировал компараторы

  • Пернес обработку пустых дат в MealRestController.getBetween()

  • Зарефакторил <T extends Comparable<? super T>> TimeUtil.isBetween(T value, T start, T end). Дженерики означают, что мы принимаем экземпляры класса, который имплементит компаратор, который умеет сравнивать T или суперклассы от T

  • Apply 1-HW2-repository.patch

Внимание: при удалении класса он остается скомпилированный у вас в target (и classpath). В этом случае (или вообще если непонятно почему проект глючит) сделайте в maven clean.

  • Apply 2-HW2-meal-layers.patch
  • Apply 3-HW2-optional-MealServlet.patch
  • Apply 4-HW2-optional-filter.patch
  • Apply 5-HW2-optional-select-user.patch

question Вопросы по HW2

Какой смысл в Objects.requireNonNull()? Если у нас объект == null он бросает NPE (NullPointException), но оно вылетит и без этого метода. What is the purpose of Objects#requireNonNull

Предусловия будет на 4м уроке. Мы падаем сразу и понятно где по стактрайсу. А не может быть потом и разбирайся откудаю.

Занятие 3:

ВНИМАНИЕ: перед накаткой патча создайте каталог test (из корня проекта путь \src\test), иначе часть файлов попадет в src\main.

  • Apply 8-add-spring-test.patch
  • Интеграция Spring и JUnit.
  • Spring Testing

Создать в pgAdmin новую базу topjava и новую роль user, пароль password

image

  • Apply 10-populate-and-init-db.patch
  • Apply 11-impl-JdbcUserRepository.patch
  • Подключение Spring Jdbc.
  • Конфигурирование DataSource. Property Placeholder

Проверьте, что в контекст Spring проекта включены оба файла конфигурации.

  • Имплементация UserRepository через Spring Jdbc Template.

Вопрос по реализации JdbcUserRepositoryImpl: в get используется query а в getByEmail - queryForObject. Где правильно и почему?

  • Apply 12-test-UserService.patch

Изменение: обертку для сравнения инстансов при тестировании перенес в сам матчер (ModelMatcher.Wrapper). Он сравнивает инстансы по переданному как параметр компаратору. Класс из видео UserTestData.TestUser стал не нужен.

  • Подготовка тестовых данных в UserServiceTest и ModelMatcher
  • Тестирование UserService.
  • Apply 13-test-logging.patch
  • Apply 14-fix-servlet.patch
  • Что такое REST? 10 Best Practices for Better RESTful API
  • Зачем нужна сортировка еды?
  • Можно ли обойтись без MapSqlParameterSource?
  • Как происходит работа с DB в тестах?
  • Как реализовывать RowMapper?
  • Мои комментарии: решения проблем разработчиком.
  • Нужен ли разработчику JavaScript?

question Ваши вопросы

Какая разница между @BeforeClass and @Before?

@BeforeClass выполняется один раз после загрузки класса (поэтому метод может быть только статический), @Before перед каждым тестом. Не ленитесь сходить в исходники по Ctrl+Enter и почитать javadoc.

Дополнение: для чистоты экземпляр тестового класса пересоздается перед каждым тестом: http://stackoverflow.com/questions/6094081/junit-using-constructor-instead-of-before

Тесты в классе в каком-то определенном порядке выполняются ("сверху вниз" например)?

Порядок по умолчанию неопределен, каждый тест должен быть автономен и не зависеть от других. См. также http://stackoverflow.com/questions/3693626/how-to-run-test-methods-in-specific-order-in-junit4

Обязательно ли разворачивать postgreSQL?

Желательно: хорошая и надежная DB:) Если совсем не хочется - можно работать со своей любимой RDBMS (поправить initDB.sql) или работать c heroku (креденшелы к нему есть в postgres.properties). На следующем уроке добавим HSQLDB, она не требует установки.

Зачем начали индексацию с 100000?

Тут уже нет "как принято". Так удобно вставлять в базу (если будет потребность) записи вручную , не мешая счетчику.

Разве не должно быть у каждой роли примари кей id и форин кей user_id ?

Отношение user <-> roles многие ко многим, делается это через таблицу-связку USER_ROLES. Но отдельной таблицы ROLES у нас нет, мы храним значение роли прямо в таблице-связке USER_ROLES. "Примари кей" тут не нужны. Есть еще варианты использовать тип enum у Postgres или хранить там INTEGER как Roles.ordinal(). При этом нельзя будет менять порядок в enum Role и добавлять новые роли можно будет только в конец: http://stackoverflow.com/questions/6789342/jpa-enum-ordinal-vs-string

Из 5-го видео - "Логика в базе - большое зло". Можно чуть поподробней об этом?

  • Есть успешные проекты с логикой в базе. Те все относительно.
  • Логика в базе - это процедуры и триггеры. Нет никакого ООП, переиспользовать код достаточно сложно, никагого рефакторинга, поиска по коду и других плюшек IDE. Нельзя делать всякие вещи типа кэширования, хранения в сесии - это все для логики на стороне java. Например json можно напрямую отдать в процедуру и там парсить и вставлять в таблицы или наоборот - собирать из таблиц и возвращать. А затем потребуется некоторая логика на стороне приложения и все равно придется этот json дополнительно разпарсивать в java. Я на таком проекте делал специальную миграцию, чтобы процедуры мигрировать не как sql скрипты, а каждую процедуру хранить как класс с историей изменений. Если логика: триггеры и простые процедуры записи-чтения, которые не требуют переиспользования кода или проект небольшой это допустимо, иначе проект становится очень трудно поддерживать.

У JUnit есть ассерты и у спринга тоже. Можно ли обойтись без JUnit?

Предусловия и JUnit-тесты совершенно разные вещи. Один другого не заменит, у нас будут предусловия в следующем уроке.

Я так понял VARCHAR быстрее, чем TEXT, когда мы работаем с небольшими записями. Наши записи будут небольшими (255). Почему вы приняли решение перейти на TEXT?

В отличие от MySql в Postgres VARCHAR и TEXT - тоже самое: http://stackoverflow.com/questions/4848964/postgresql-difference-between-text-and-varchar-character-varying

Зачем при создании таблицы мы создаем CREATE UNIQUE INDEX и CREATE INDEX. При каких запросах он будет использоваться?

UNIQUE индекс нужен для обеcпечения уникальности, DB не даст сделать одинаковый индекс. Индексы используется для скорости выполнения запросов. Обычно они задействуются, когда в запросе есть условия, на которые сделан индекс. Узнать по конкретному запросу можно запросив план запроса: см. Оптимизация запросов. Основы EXPLAIN в PostgreSQL. На измерение производительности с индексами посмотрим в следующем уроке.

А это нормально, что у нас в базе у meals есть userId, а в классе - нет?

Что значит - "нормально"? Приложение работает. Ненормально, когда в приложении есть "лишний" код, который не используется. Для ORM он нам понадобится- мы ссылку на User добавим.

Почему мы использует 1 БД sequence на разные сущности?

Мы будем использовать Hibernate, по умолчанию он делает глобальный sequence на все таблицы. В этом подходе есть как плюсы, так и минусы, из плюсов - удобно делать ссылки в коде и в таблицах на при наследовании и мапы в коде. В дополнение: Configure Hibernate to create separate sequence for each table by default.

hw Домашнее задание HW03

  1. Понять, почему перестали работать SpringMain/InMemoryAdminRestControllerTest/ InMemoryAdminRestControllerSpringTest
  2. Дополнить скрипты создания и инициализации базы таблицой MEALS. Запустить скрипты на вашу базу (через Run). Порядок таблиц при DROP и DELETE важен, если они связаны fk. Проверьте, что ваши скрипты работают
  3. Реализовать через Spring JDBC Template JdbcMealRepositoryImpl 3.1. сделать каждый метод за один SQL запрос 3.2. userId в класс Meal вставлять НЕ надо (для UI и REST это лишние данные, userId это id залогиненного пользователя) 3.3. JbdcTemplate работает через сеттеры. Вместе с конструктором по умолчанию их нужно добавить в Meal 3.4. Cписок еды должен быть отсортирован (тогда мы его сможем сравнивать с тестовыми данными). Кроме того это требуется для UI и API: последняя еда наверху.
  4. Проверить работу MealServlet, запустив приложение

Optional

  1. Сделать тестовые данные MealTestData, АНАЛОГИЧНЫЕ пропопулированным в populateDB.sql. Сравниваем данные через готовый MATCHER (по умолчанию)
  2. Сделать MealServiceTest из MealService (Ctrl+Shift+T и выбрать JUnit4) и реализовать тесты.
  3. Сделать тесты на чужих юзеров (delete, get, update) с тем чтобы получить NotFoundException и тесты на update чужой еды.
  4. Предложить решение, как почнинить SpringMain/ InMemory*Test. InMemory*Test предполагает использовать нашу реализацию репозитория в памяти
  5. Сделать индексы к таблице Meals.

error Решение проблем

В JUnit тестах проблама с кодировкой

См. http://stackoverflow.com/a/17671104/548473, нужно в pom.xml в plugins добавить:

      <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.19.1</version>
          <configuration>
              <argLine>-Dfile.encoding=UTF-8</argLine>
          </configuration>
      </plugin>

Из каталога main не видятся классы/ресурсы в test

Все что находится в test используется только для тестов и недоступно в основном коде

Из IDEA не видятся ресурсы в каталоге test

  • Сделайте Reimport All в Maven окне

image

  • Поставьте чекбокс Check test files в Inspections. Spring test контекст не надо включать в Spring Facets проекта.

image

error Проверка по HW03 (сначала сделайте самостоятельно!)

  • В MealTestData еду делайте константами. Не надо Map конструкций!
  • SQL case-insensitive, не надо писать в стиле Camel. В POSTGRES возможно case-sensitive значения в кавычки заключать (но не нужно).
  • ЕЩЕ РАЗ: InMemory тесты должны идти на InMemory репозитории
  • В MealTestData можно использовать дефолтный компаратор
  • Проверьте, что возвращает JdbcMealRepositoryImpl при обновлении чужой еды