diff --git a/.codacy.yml b/.codacy.yml new file mode 100644 index 000000000000..311a8f4e0029 --- /dev/null +++ b/.codacy.yml @@ -0,0 +1,5 @@ +--- +exclude_paths: + - 'src/main/webapp/**' + - '**.md' + - '**.sql' \ No newline at end of file diff --git a/.gitignore b/.gitignore index 73e6d9e3dd11..42ff323f7d38 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .idea out target +path_arhive *.iml log *.patch diff --git a/README.md b/README.md index 228b708b7094..aa48441c6719 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +[](https://www.codacy.com/gh/JavaWebinar/topjava/dashboard) + Java Enterprise Online Project =============================== Разработка полнофункционального 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. @@ -14,199 +16,3 @@ Java Enterprise Online Project ## Описание и план проекта ### Демо разрабатываемого приложения ### [Изменения проекта (Release Notes)](ReleaseNotes.md) -### Требования к участникам, Wiki -### Составление резюме, подготовка к интервью, поиск работы - -Вводное занятие (обязательно смотреть все видео) -=============== -##  1. Осваиваем Java Enterprise. Трудоустройство. Ответы на вопросы. -- Слайды презентации -- Java Tools and Technologies Landscape Report 2016 -- [Java in 2017 Survey](http://www.baeldung.com/java-in-2017) -- Из юниоров в разработчики: получаем первую работу - -#### Spring Pet-Clinic -- Spring PetClinic Sample Application -- Presentation - -##  2. Системы управления версиями. Git. -- **Wiki по ведению проекта в Git** -- Система управления версиями. VCS/DVSC. -- Ресурсы: - - Интерактивная Git обучалка - - Еще одна интерактивная обучалка, по-русски - - Книга Git - - Working with remote repositories - - Видео по обучению Git - - Git Overview - - [Основы Git за 20 минут](https://www.youtube.com/watch?v=TMeZGvtQnT8) - - [Git - для новичков](https://www.youtube.com/watch?list=PLY4rE9dstrJyTdVJpv7FibSaXB4BHPInb&v=PEKN8NtBDQ0) - -##  3. Работа с проектом (выполнять инструкции) -**ВНИМАНИЕ: выбирайте для проекта простой пусть без пробелов и русских букв, например (Windows) `c:\projects\topjava\`. Иначе впоследствии будут проблемы** -### Патч [prepare_to_HW0.patch](https://drive.google.com/file/d/1LNPpu9OkuCpfpD8ZJHO-o0vwu49p2i5M) (скачать и положить в каталог вашего проекта) - -> Проект постоянно улучшается, поэтому видео иногда отличается от кода проекта. Изменения указываю после видео: -> - переименовал класс `UserMealWithExceed` и его поле `exceed` в `UserMealWithExcess.excess` -> - в `UserMeals/UserMealWithExcess` поля изменились на `private` -> - обновил данные `UserMealsUtil.meals` и переименовал некоторые пременные, поля и методы -> - добавил `UserMealWithExcess.toString()` и метод для выполнения _Optional домашнего задания_ - - -## Инструкция по шагам (из видео): -- Установить ПО (git, JDK8, IntelliJ IDEA, Maven) -- Создать аккаунт на GitHub -- Сделать Fork **ЭТОГО** проекта (https://github.com/JavaOPs/topjava) -- Сделать локальный репозиторий проекта: -
git clone https://github.com/[Ваш аккаунт]/topjava.git-- Открыть и настроить проект в IDEA - - Выставить кодировку UTF-8 в консоли - - Поставить кодировку UTF-8 - - Опционально: Поменять фонт по умолчанию (DejaVu) или на **новый [JetBrains Mono](https://habr.com/ru/company/jugru/news/t/484134/)** -- По ходу видео сделать Apply Patch... скаченного патча Prepare_ to_ HW0.patch -- Закоммитить и запушить изменения (commit + push) -- Сделать ветку домашнего задания -- Выполнить задание и залить на GitHub (commit + push) -- Переключиться в основную ветку проекта master. - -##  Домашнее задание HW0 -``` -Реализовать метод `UserMealsUtil.filteredByCycles` через циклы (`forEach`): -- должны возвращаться только записи между `startTime` и `endTime` -- поле `UserMealWithExcess.excess` должно показывать, - превышает ли сумма калорий за весь день значение `caloriesPerDay` - -Т.е `UserMealWithExcess` - это запись одной еды, но поле `excess` будет одинаково для всех записей за этот день. - -- Проверьте результат выполнения ДЗ (можно проверить логику в http://topjava.herokuapp.com , список еды) -- Оцените Time complexity алгоритма. Если она больше O(N), например O(N*N) или N*log(N), сделайте O(N). -``` -- Java 8 Date and Time API -- Алгоритмы и структуры данных для начинающих: сложность алгоритмов -- [Головач: сложность алгоритмов в теме коллекций](https://www.youtube.com/watch?v=Ek9ijOiplNE&feature=youtu.be&t=778) -- Time complexity -- Временная сложность алгоритма -- Вычислительная сложность - -#### ВНИМАНИЕ: варианты Optional делайте в `UserMealsUtil` в одной ветке в разных методах. Проще делать, проще проверять - -### Optional (Java 8 Stream API) -``` -Реализовать метод `UserMealsUtil.filteredByStreams` через Java 8 Stream API. -``` -- Видео: Доступно о Java 8 Lambda -- Java 8: Lambda выражения -- Java 8: Потоки -- Pуководство по Java 8 Stream -- Java 8 Stream API в картинках и примерах -- [7 способов использовать groupingBy в Stream API](https://habrahabr.ru/post/348536) -- Лямбда-выражения в Java 8 -- A Guide to Java 8 -- Шпаргалка Java Stream API -- Алексея Владыкин: Элементы функционального программирования в Java -- Yakov Fain о новом в Java 8 -- stream.map vs forEach -- Дополнительно - - [Сергей Куксенко — Stream API, часть 1](https://www.youtube.com/watch?v=O8oN4KSZEXE) - - [Сергей Куксенко — Stream API, часть 2](https://www.youtube.com/watch?v=i0Jr2l3jrDA) - -### Optional 2 (+5 бонусов) -Сделать реализацию со сложностью O(N) (обратите внимание на п.13 замечаний): -- циклом за 1 проход по `List
+ * Handling Hibernate lazy-loading
+ *
+ * @link https://github.com/FasterXML/jackson
+ * @link https://github.com/FasterXML/jackson-datatype-hibernate
+ * @link https://github.com/FasterXML/jackson-docs/wiki/JacksonHowToCustomSerializers
+ */
+public class JacksonObjectMapper extends ObjectMapper {
+
+ private static final ObjectMapper MAPPER = new JacksonObjectMapper();
+
+ private JacksonObjectMapper() {
+ registerModule(new Hibernate5Module());
+
+ registerModule(new JavaTimeModule());
+ configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
+
+ setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
+ setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
+ setSerializationInclusion(JsonInclude.Include.NON_NULL);
+ }
+
+ public static ObjectMapper getMapper() {
+ return MAPPER;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/ru/javawebinar/topjava/web/json/JsonUtil.java b/src/main/java/ru/javawebinar/topjava/web/json/JsonUtil.java
new file mode 100644
index 000000000000..d3bf1ac0435f
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/web/json/JsonUtil.java
@@ -0,0 +1,49 @@
+package ru.javawebinar.topjava.web.json;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectReader;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import static ru.javawebinar.topjava.web.json.JacksonObjectMapper.getMapper;
+
+public class JsonUtil {
+
+ public static
+ * Comparing actual and expected objects via AssertJ
+ * Support converting json MvcResult to objects for comparation.
+ */
+public class MatcherFactory {
+
+ public static Filter separately
+ *
+ */
+ public List
+
+
+ ${status}
+
+ ${message}
+
+ Spring Security,
+ Spring MVC,
+ Spring Data JPA,
+ Spring Security
+ Test,
+ Hibernate ORM,
+ Hibernate Validator,
+ SLF4J,
+ Json Jackson,
+ JSP,
+ JSTL,
+ Apache Tomcat,
+ WebJars,
+ DataTables,
+ EHCACHE,
+ PostgreSQL,
+ HSQLDB,
+ JUnit 5,
+ Hamcrest,
+ AssertJ,
+ jQuery,
+ jQuery plugins,
+ Bootstrap.
+
+ <%--https://getbootstrap.com/docs/4.0/components/card/--%>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${userTo.name}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
" + errorInfo.type + "
" + errorInfo.detail,
+ type: "error",
+ layout: "bottomRight"
+ });
+ failedNote.show()
+}
\ No newline at end of file
diff --git a/src/main/webapp/resources/js/topjava.meals.js b/src/main/webapp/resources/js/topjava.meals.js
new file mode 100644
index 000000000000..0b3e8e7e8d84
--- /dev/null
+++ b/src/main/webapp/resources/js/topjava.meals.js
@@ -0,0 +1,119 @@
+const mealAjaxUrl = "profile/meals/";
+
+// https://stackoverflow.com/a/5064235/548473
+const ctx = {
+ ajaxUrl: mealAjaxUrl,
+ updateTable: function () {
+ $.ajax({
+ type: "GET",
+ url: mealAjaxUrl + "filter",
+ data: $("#filter").serialize()
+ }).done(updateTableByData);
+ }
+}
+
+function clearFilter() {
+ $("#filter")[0].reset();
+ $.get(mealAjaxUrl, updateTableByData);
+}
+
+// http://api.jquery.com/jQuery.ajax/#using-converters
+$.ajaxSetup({
+ converters: {
+ "text json": function (stringData) {
+ var json = JSON.parse(stringData);
+ if (typeof json === 'object') {
+ $(json).each(function () {
+ if (this.hasOwnProperty('dateTime')) {
+ this.dateTime = this.dateTime.substr(0, 16).replace('T', ' ');
+ }
+ });
+ }
+ return json;
+ }
+ }
+});
+
+$(function () {
+ makeEditable({
+ "columns": [
+ {
+ "data": "dateTime"
+ },
+ {
+ "data": "description"
+ },
+ {
+ "data": "calories"
+ },
+ {
+ "render": renderEditBtn,
+ "defaultContent": "",
+ "orderable": false
+ },
+ {
+ "render": renderDeleteBtn,
+ "defaultContent": "",
+ "orderable": false
+ }
+ ],
+ "order": [
+ [
+ 0,
+ "desc"
+ ]
+ ],
+ "createdRow": function (row, data, dataIndex) {
+ $(row).attr("data-meal-excess", data.excess);
+ }
+ });
+
+// http://xdsoft.net/jqplugins/datetimepicker/
+ var startDate = $('#startDate');
+ var endDate = $('#endDate');
+ startDate.datetimepicker({
+ timepicker: false,
+ format: 'Y-m-d',
+ formatDate: 'Y-m-d',
+ onShow: function (ct) {
+ this.setOptions({
+ maxDate: endDate.val() ? endDate.val() : false
+ })
+ }
+ });
+ endDate.datetimepicker({
+ timepicker: false,
+ format: 'Y-m-d',
+ formatDate: 'Y-m-d',
+ onShow: function (ct) {
+ this.setOptions({
+ minDate: startDate.val() ? startDate.val() : false
+ })
+ }
+ });
+
+ var startTime = $('#startTime');
+ var endTime = $('#endTime');
+ startTime.datetimepicker({
+ datepicker: false,
+ format: 'H:i',
+ onShow: function (ct) {
+ this.setOptions({
+ maxTime: endTime.val() ? endTime.val() : false
+ })
+ }
+ });
+ endTime.datetimepicker({
+ datepicker: false,
+ format: 'H:i',
+ onShow: function (ct) {
+ this.setOptions({
+ minTime: startTime.val() ? startTime.val() : false
+ })
+ }
+ });
+
+ $('#dateTime').datetimepicker({
+ format: 'Y-m-d H:i'
+ });
+});
\ No newline at end of file
diff --git a/src/main/webapp/resources/js/topjava.users.js b/src/main/webapp/resources/js/topjava.users.js
new file mode 100644
index 000000000000..bb8863a8f441
--- /dev/null
+++ b/src/main/webapp/resources/js/topjava.users.js
@@ -0,0 +1,86 @@
+const userAjaxUrl = "admin/users/";
+
+// https://stackoverflow.com/a/5064235/548473
+const ctx = {
+ ajaxUrl: userAjaxUrl,
+ updateTable: function () {
+ $.get(userAjaxUrl, updateTableByData);
+ }
+}
+
+function enable(chkbox, id) {
+ var enabled = chkbox.is(":checked");
+// https://stackoverflow.com/a/22213543/548473
+ $.ajax({
+ url: userAjaxUrl + id,
+ type: "POST",
+ data: "enabled=" + enabled
+ }).done(function () {
+ chkbox.closest("tr").attr("data-user-enabled", enabled);
+ successNoty(enabled ? "common.enabled" : "common.disabled");
+ }).fail(function () {
+ $(chkbox).prop("checked", !enabled);
+ });
+}
+
+// $(document).ready(function () {
+$(function () {
+ makeEditable({
+ "columns": [
+ {
+ "data": "name"
+ },
+ {
+ "data": "email",
+ "render": function (data, type, row) {
+ if (type === "display") {
+ return "" + data + "";
+ }
+ return data;
+ }
+ },
+ {
+ "data": "roles"
+ },
+ {
+ "data": "enabled",
+ "render": function (data, type, row) {
+ if (type === "display") {
+ return "";
+ }
+ return data;
+ }
+ },
+ {
+ "data": "registered",
+ "render": function (date, type, row) {
+ if (type === "display") {
+ return date.substring(0, 10);
+ }
+ return date;
+ }
+ },
+ {
+ "orderable": false,
+ "defaultContent": "",
+ "render": renderEditBtn
+ },
+ {
+ "orderable": false,
+ "defaultContent": "",
+ "render": renderDeleteBtn
+ }
+ ],
+ "order": [
+ [
+ 0,
+ "asc"
+ ]
+ ],
+ "createdRow": function (row, data, dataIndex) {
+ if (!data.enabled) {
+ $(row).attr("data-user-enabled", false);
+ }
+ }
+ });
+});
\ No newline at end of file
diff --git a/src/main/webapp/test.html b/src/main/webapp/test.html
new file mode 100644
index 000000000000..e50b3327754f
--- /dev/null
+++ b/src/main/webapp/test.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/java/ru/javawebinar/topjava/ActiveDbProfileResolver.java b/src/test/java/ru/javawebinar/topjava/ActiveDbProfileResolver.java
new file mode 100644
index 000000000000..da3bec700df3
--- /dev/null
+++ b/src/test/java/ru/javawebinar/topjava/ActiveDbProfileResolver.java
@@ -0,0 +1,19 @@
+package ru.javawebinar.topjava;
+
+import org.springframework.lang.NonNull;
+import org.springframework.test.context.support.DefaultActiveProfilesResolver;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+//http://stackoverflow.com/questions/23871255/spring-profiles-simple-example-of-activeprofilesresolver
+public class ActiveDbProfileResolver extends DefaultActiveProfilesResolver {
+ @Override
+ public @NonNull
+ String[] resolve(@NonNull Class> aClass) {
+ List