Design and implement a REST API using Hibernate/Spring/SpringMVC (or Spring-Boot) without frontend.
The task is:
Build a voting system for deciding where to have lunch.
2 types of users: admin and regular users Admin can input a restaurant and it's lunch menu of the day (2-5 items usually, just a dish name and price) Menu changes each day (admins do the updates) Users can vote on which restaurant they want to have lunch at Only one vote counted per user If user votes again the same day: If it is before 11:00 we asume that he changed his mind. If it is after 11:00 then it is too late, vote can't be changed Each restaurant provides new menu each day.
-
основные классы приложения: [Dish, Restaurant, User, Vote]
-
все данные хранятся в базе данных [HSQLDB]
-
для обслуживания запросов анонимных пользователей (anonymous) и авторизованных (profile) формируется список меню ресторанов в классе ТО [Menu]
-
бизнес-логика в VoteRestController. Голосовать можно один раз в день, до 11:00 голос можно изменять.
-
репозиторий [Spring Data JPA]
-
транзакционность [Springframework]
-
пул коннектов [Tomcat]
-
кеш [EhCache-based Cache], кешируются "все меню на сегодня" в RestaurantRestController, метод getAllWithDishesOfDate() это позволяет не обращаться к DB при стандартном запросе актуального списка меню
-
базовая авторизация [SpringSecurity], доступ к ресурсам по ролям:
/rest/admin/**'
- 'ADMIN'/rest/profile/**
- 'USER'/anonymous/**
- свободный доступ для просмотра актуальных меню -
тестирование REST контроллеров [Junit5]
-
обработка ошибок [ExceptionInfoHandler, GlobalExceptionHandler]
-
curl
- команды тестирования голосований:
curl -L -X GET 'http://localhost:8080/topjava/anonymous' \ -H 'Authorization: Basic Og=='
curl -L -X GET 'http://localhost:8080/topjava/anonymous/restaurants/100003' \ -H 'Authorization: Basic Og=='
curl -L -X GET 'http://localhost:8080/topjava/rest/profile/votes/100016' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X GET 'http://localhost:8080/topjava/rest/profile/votes' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X GET 'http://localhost:8080/topjava/rest/profile/votes/restaurant?restaurantId=100002' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X GET 'http://localhost:8080/topjava/rest/profile/votes/date?localDate=2020-06-30' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu
curl -L -X GET 'http://localhost:8080/topjava/rest/profile/votes/between?startDate=2020-06-30&endDate=2020-07-29' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu
curl -L -X PUT 'http://localhost:8080/topjava/rest/profile/votes?voteId=100015&restaurantId=100003' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu
curl -L -X POST 'http://localhost:8080/topjava/rest/profile/votes?restaurantId=100002' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X DELETE 'http://localhost:8080/topjava/rest/profile/votes/100016' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X GET 'http://localhost:8080/topjava/rest/profile/menus' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X GET 'http://localhost:8080/topjava/rest/profile/menus/today' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X GET 'http://localhost:8080/topjava/rest/profile/menus/restaurants/100002' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X GET 'http://localhost:8080/topjava/rest/profile/menus/menu/100002?localDate=2020-07-30' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X GET 'http://localhost:8080/topjava/rest/profile/menus/menu?restaurantName=%D0%9F%D1%80%D0%B0%D0%B3%D0%B0&localDate=2020-07-30' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X GET 'http://localhost:8080/topjava/rest/profile/menus/date?localDate=2020-07-30' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X GET 'http://localhost:8080/topjava/rest/admin/votes' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X GET 'http://localhost:8080/topjava/rest/admin/votes/100015' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X GET 'http://localhost:8080/topjava/rest/admin/votes/restaurants/100003' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X GET 'http://localhost:8080/topjava/rest/admin/votes/date?localDate=2020-07-29' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X GET 'http://localhost:8080/topjava/rest/admin/votes/date?localDate=2020-07-29' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X GET 'http://localhost:8080/topjava/rest/admin/votes/users?id=100000' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X GET 'http://localhost:8080/topjava/rest/admin/votes/between?startDate=2020-07-30&endDate=2020-07-30&userId=100000' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X PUT 'http://localhost:8080/topjava/rest/admin/votes?voteId=100015&restaurantId=100003' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu
curl -L -X POST 'http://localhost:8080/topjava/rest/admin/votes?restaurantId=100002' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X DELETE 'http://localhost:8080/topjava/rest/admin/votes/100015' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X GET 'http://localhost:8080/topjava/rest/admin/restaurants' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X GET 'http://localhost:8080/topjava/rest/admin/restaurants/100003' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X GET 'http://localhost:8080/topjava/rest/admin/restaurants/names?restaurantName=%D0%92%D0%B5%D0%BD%D0%B5%D1%86%D0%B8%D1%8F' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu
curl -L -X GET 'http://localhost:8080/topjava/rest/admin/restaurants/100003/date?localDate=2020-07-30' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X GET 'http://localhost:8080/topjava/rest/admin/restaurants/dishes' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X GET 'http://localhost:8080/topjava/rest/admin/restaurants/menus?localDate=2020-07-30' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X POST 'http://localhost:8080/topjava/rest/admin/restaurants' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu' \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "", "name": "НовыйРесторан", "dishes": null }'
curl -L -X PUT 'http://localhost:8080/topjava/rest/admin/restaurants/100003' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu' \ -H 'Content-Type: application/json' \ --data-raw '{ "id": 100003, "name": "Прага_обновленный_2", "dishes": null }'
curl -L -X DELETE 'http://localhost:8080/topjava/rest/admin/restaurants/100002' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X GET 'http://localhost:8080/topjava/rest/admin/dishes' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X GET 'http://localhost:8080/topjava/rest/admin/dishes/100010?restaurantId=100003' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X GET 'http://localhost:8080/topjava/rest/admin/dishes/menus?restaurantId=100003&date=2020-07-30' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X POST 'http://localhost:8080/topjava/rest/admin/dishes?restaurantId=100002' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu' \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "", "name": "Новая еда", "localDate": "2020-07-29", "price": 0.2 }'
curl -L -X PUT 'http://localhost:8080/topjava/rest/admin/dishes/100005?restaurantId=100002' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu' \ -H 'Content-Type: application/json' \ --data-raw '{ "id": 100005, "name": "Updated Чай", "localDate": "2020-06-29", "price": 0.2 }'
curl -L -X DELETE 'http://localhost:8080/topjava/rest/admin/dishes/100014/restaurants/100003' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X GET 'http://localhost:8080/topjava/rest/profile/users/100001' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X PUT 'http://localhost:8080/topjava/rest/profile/users/100001' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu' \ -H 'Content-Type: application/json' \ --data-raw '{ "id": 100001, "name": "updatedUser", "email": "[email protected]", "password": "updated", "registered": "2020-07-30T06:00:00.000+00:00", "roles": [ "USER" ] }'
curl -L -X DELETE 'http://localhost:8080/topjava/rest/profile/users/100001' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X GET 'http://localhost:8080/topjava/rest/admin/users' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X GET 'http://localhost:8080/topjava/rest/admin/users/100000' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X GET 'http://localhost:8080/topjava/rest/admin/users/[email protected]' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X PATCH 'http://localhost:8080/topjava/rest/admin/users/100001?enabled=false' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'
curl -L -X POST 'http://localhost:8080/topjava/rest/admin/users' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu' \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "", "name": "NewUser", "email": "[email protected]", "password": "newPassword", "registered": "2020-01-30T06:00:00.000+00:00", "roles": [ "USER" ] }'
curl -L -X PUT 'http://localhost:8080/topjava/rest/admin/users/100000' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu' \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "100000", "name": "UpdateUser", "email": "[email protected]", "password": "updatePassword", "registered": "2020-01-30T06:00:00.000+00:00", "roles": [ "USER" ] }'
curl -L -X DELETE 'http://localhost:8080/topjava/rest/admin/users/100001' \ -H 'Authorization: Basic YWRtaW5AZ21haWwuY29tOmFkbWlu'