Skip to content
Vladimir edited this page Feb 9, 2019 · 1 revision

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

  • Браузер кэширует javascript и css. Если изменения не работают, обновите приложение в браузере (в хроме Ctrl+F5)
  • При удалении файлов не забывайте делать clean: mvn clean

error Правка и рефакторинг

Apply 8_0_1_fix.patch

  • Небольшая правка кода

Apply 8_0_2_test_refactoring.patch

  • Рефакторинг тестов
    • RootControllerTest: вместо сравнения по полям можно использовать наш UserTestData.assertMatch с помощью AssertionMatcher адаптера. Методы сравнения по полям в hamcrest-all больше не нужны, заменил на hamcrest-core.
    • Вместо сериализации ожидаемых объектов в json и сравнение с ответом в MVC через content().json() красивее десериализовать ответ в объект и сравнивать уже объекты через наши assertMatch c учетом игнорируемых полей. jsonassert становится не нужен.

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

video 1. HW7

Apply 8_01_HW07_controller_test.patch

В RootControllerTest.testMeals() сделал проверку через model().attribute("meals", expectedValue). Сравнение происходит через MealTo.equals(), который мы можем переопределить, т.к. он Transfer Object, не является сущностью (Entity).


  • Persistent classes implementing equals and hashcode: переопределять equals()/hashCode() необходимо, если
    • использовать Entity в Set (рекомендовано для many ассоциаций), либо как ключи в HashMap
    • использовать reattachment of detached instances (те манипулировать одним Entity в нескольких транзакциях/сессиях).
  • Оптимально использовать уникальные неизменяемые бизнес поля, но обычно таких нет, и, чаще всего, используются PK с ограничением, что он может быть null у новых объектов и нельзя объекты сравнивать через equals в бизнес-логике (например тестах). Equals() and hashcode() when using JPA and Hibernate

Apply 8_02_HW07_rest_controller.patch

  • Как и для юзера сериализуем json ответ контроллера и сравниваем через ResultMatcher. Для MealTo используем в сравнении isEqualTo.

Apply 8_03_HW07_formatters.patch

Перенес форматтеры в подпакет web, тк они используются Spring MVC

Apply 8_04_HW07_soapui_curl.patch

Добавил примеры запросов curl в config/curl.md

Занятие 8:

Apply 8_05_webjars.patch

  • Обновил jQuery до 3.x, Bootstrap до 4.x
  • УБРАЛ из проекта Dandelion обертку к datatables:
    • не встречал нигде, кроме Spring Pet Clinic;
    • поддержка работы с datatables через Dandelion оказалось гораздо более трудоемкое, чем работа с плагином напрямую.
  • Исключил из зависимостей webjars ненужные jQuery

Apply 8_06_bootstrap4.patch

JSP полезны, если надо с сервера отдать статический html с серверной логикой (условия, циклы), сформированный на основе модели. Для динамической отрисовки таблицы мы будем использовать REST и JSON на 9м уроке (работа с datatables через Ajax).

Apply 8_07_ajax_datatables.patch

Apply 8_08_update_js.patch

Apply 8_09_notification.patch

  • Правка к видео: путь в intercept-url должен быть полный: pattern="/rest/admin/**"
  • В Spring Security 4.x по умолчанию включен csrf (защита от межсайтовой подделки запроса). Выключил, включим на 10-м занятии.
  • В Spring Security 5.x по умолчанию пароль кодируется. Выключил, включим на 10-м занятии.

Apply 8_10_add_security.patch

question почему для spring-security версия не `${spring.version}' (5.1.2.RELEASE) ?

curl -v -H 'Authorization: Basic dXNlckB5YW5kZXgucnU6cGFzc3dvcmQ=' http://localhost:8080/topjava/rest/profile/meals

аналогична

curl -v --user [email protected]:password http://localhost:8080/topjava/rest/profile/meals

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

Что делает код?

$('.delete').click(function () {
        deleteRow($(this).attr("id"));
    });

На все элементы DOM с классом delete вешается обработчик события click который вызывает функцию deleteRow. Классы в html разделяются через пробел. См. селекторы в jQuery

тянет ли bootstrap за собой jQuery?

Bootstrap css это стили (форматирование), Bootstrap js зависит от jQuery: http://stackoverflow.com/questions/14608681/can-i-use-twitter-bootstrap-without-jquery#answer-14608772

А где реально этот путь "classpath:/META-INF/resources/webjars"?

Внутри подключаемых webjars ресурсы лежат по пути /META-INF/resources/webjars/... Не поленитесь посмотреть на них через Ctrl+Shift+N. Все подключаемые jar попадают в classpath и ресурсы доступны по этому пути.

У меня webjars зависимость лежит внутри ".m2\repository\org\webjars". С чем это может быть связано?

Maven скачивает все депенденси в local repository, который по умолчанию находится в ~/.m2. Каталог по умолчанию можно переопределить в APACHE-MAVEN-HOME\conf\settings.xml, элемент localRepository.

WEBJARS лежат вообще в другом месте WEB-INF\lib*. Биндим mapping="/webjars/*" на реальное положение jar в ware, откуда spring знает где искать наш jquery ?

В war в WEB-INF/lib/* лежат все jar, которые попадают к classpath. Spring при обращении по url /webjars/ ищет по пути биндинга <mvc:resources mapping="/webjars/ " location="classpath:/META-INF/resources/webjars/"/> по всему classpath (то же самое как распаковать все jar в один каталог) в META-INF/resources/webjars/. В этом месте во всех jar, которые мы подключили из webjars лежат наши ресурсы.

Как можно в браузере сбросить введенный пароль базовой авторизации?

Проще всего делать новый запрос в новой анонимной вкладке (Ctrl+Shift+N в Chrome)

Оптимально ли делать доступ к статическим ресурсам (css, js, html) через webjars ?

На продакшене под нагрузкой статические ресурсы лучше всего держать не в war, а снаружи. Доступ к ним делается либо через конфигурирование Tomcat, но чаще всего через прокси, например Nginx

Как по REST определяется залогиненный юзер? Аутентификация происходит при каждом запросе?

Способы RESTful Authentication. Мы будем использовать 2: coockie + http session (на след. уроке) и Basic Authentication с аутентификацией при каждом запросе.

Почему @RequestParam не работает в PUT и DELETE запросах?

По спецификации Servlet API параметры в теле для PUT, DELETE, TRACE методах не обрабатываются (только в url). Те. можно:

  • использовать POST
  • передавать параметры в url
  • использовать HttpPutFormContentFilter фильтр
  • настроить Tomcat в обход спецификации.

См. Handle request parameters for an HTTP PUT method

Данные между браузером и ajax гоняются в виде json? Почему в AdminAjaxController у методов delete и createOrUpdate нет в аннотациях параметра consumes = MediaType.APPLICATION_JSON_VALUE ?

Посмотреть на данные между приложением и браузером можно (и нужно!) в браузере (вкладка Network в Инструментах разработчика, F12 в Хроме). Зависит от того, как их отправляем из браузера и из приложения. Данные формы обычно передаются просто параметрами. APPLICATION_JSON_VALUE в контроллере нужно, только если параметры отдаются/принимаются в формате JSON.

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

  • 1: Перевести meals на datatables (meals.jsp, MealAjaxController).
    • 1.1 Реализовать добавление записи еды через модальное окно Bootstrap и удаление еды по ajax (БЕЗ редактирования).
    • 1.2 При вставке данных по AJAX пропадает все JSP форматирование, чинить перерисовку НЕ надо. Следующий урок- будем делать datatable по AJAX и форматирование на стороне клиента.
  • 2: Т.к. HTML атрибут id у каждого элемента документа должен быть уникален, нужно избавиться от дублирования id="${user.id}" в строках таблиц users (users.jsp) (переместить атрибут id в тэг <tr> или передавать в качестве параметра функций через onclick)

Optional.

  • 3: Перевести работу фильтра на AJAX. Попробуйте после модификации таблицы (например добавлении записи) обновлять ее также с учетом фильтра.
  • 4: Сделать кнопку сброса фильтра.
  • 5: Реализовать enable/disable User через checkbox в users.jsp с сохранением в DB. Неактивных пользователей выделить css стилем. Проверьте, как у вас первоначально (или по F5) отображаются неактивные пользователи (если меняете css при enable/disable)

error Подсказки по HW08

  • 1: enable/disable делать c @Transactional (можно реализовать как на уровне репозитория, так и на уровне сервиса через несколько sql, которые должны быть в одной транзакции)
  • 2: в topjava.common.js следует выносите только общие скрипты (cкрипты еды размещайте в topjava.meals.js, пользователей в topjava.users.js)
  • 3: если в контроллер приходит null проверте в Network вкладке браузера в каком формате приходят данные и в каком формате в контроллере вы их принимаете (consumes).
  • 4: при реализации enable/disable лучше явно указывать нужное состояние, чем переключать на противоположное. Если параллельно вам кто-то изменит состояние, то будет несоответствие UI и DB. Не забудьте про enable/disable тесты.
Clone this wiki locally