JavaRush /Java блог /Random UA /Тестове завдання на працевлаштування, давайте розберемося...
timurnav
21 рівень

Тестове завдання на працевлаштування, давайте розберемося.

Стаття з групи Random UA
Друзі, всім привіт. хочу поділитися з вами досвідом вирішення тестового завдання на позицію java developer'а російської компанії. Відразу скажу, реалізувати основний функціонал завдання не становить особливої ​​складності, але як завжди важливі деталі та дрібниці, які завадабо мені здати його в строк, за завданням мені так нічого і не відповіли – вакансія у них вже закрита була коли я висилав їм. Пропоную розібратися із завданням чи все я зробив, що від мене вимагалося. А тим хто поняття не має, як його зробити, я додам багато води, про те, як я з ним оброблявся. Якщо це раптом комусь цікаво - ласкаво просимо під кат. Відразу скажу, що тут все рішення я викладати не буду, але буде багато пояснень для початківців, якщо кому не цікаво читати мої вабовання, ось вам проект на github Почну з самого тексту завдання.
Тестове завдання №1
Опис: Сервер API (JSON HTTP API) Засоби розробки: Java Framework: Play Framework 2.4 (або вище) або Spring boot 1.2.3 (або вище) База даних: MySQL Протокол: HTTP, порт 80 Функціонал (запити):
  1. Завантажувач.
    • Передаємо на сервер файл (картинка аватара JPG).
    • Зберігаємо картинку в каталозі на сервері.
    • Відповідь сервера – внутрішній URI картинки.
  2. Додавання нового користувача.
    • Передаємо на сервер персональні дані користувача (URI картинки, ім'я користувача, email тощо).
    • Зберігаємо інформацію у базі даних.
    • Відповідь сервера – унікальний ID нового користувача.
  3. Отримання інформації про користувача.
    • Передаємо сервер унікальний ID користувача.
    • Читаємо інформацію з бази даних.
    • Відповідь сервера – персональні дані користувача (див. вище).
  4. Зміна статусу користувача (Online, Offline).
    • Передаємо на сервер унікальний ID користувача та новий статус (Online, Offline).
    • Змінюємо статус користувача.
    • Відповідь сервера – унікальний ID користувача, новий та попередній статус.
    Примітка: на сервері виконується запит до зовнішнього API/бази даних. Так як це спрощене тестове завдання необхідно реалізувати "заглушку" з імітацією поводження та затримкою за часом 5-10 сек.
  5. Статистика сервера.
    • Передаємо параметри на сервер: 1. статус клієнтів (Online, Offline або відсутня); 2. унікальний ID (timestamp) запиту (може бути відсутнім)
    • Відповідь сервера - список користувачів зі статусами та URI картинки, а також унікальний ID (timestamp) запиту.
    Примітка: Якщо у запиті є параметри, сервер повинен фільтрувати по них свою відповідь. Якщо запит має унікальний ID (timestamp) запиту (отриманий раніше), то сервер повинен повернути тільки користувачів, у яких змінабося статуси після (за часом) цього унікального ID (timestamp).
Обов'язкові вимоги:
- RESTful. - Усі дані у форматі JSON. - Сервер API має бути спроектований з урахуванням того, що запити 3 та 5 має найвищий пріоритет (стосовно запитів 1, 2, 4) та мають бути виконані максимально швидко. - Обробка помилок.
Необов'язкові вимоги (бажано):
- документування коду. - Архітектура Сервера API має бути розрахована на високе навантаження та масштабування. – Тести.
Результат тестового завдання:
- Результат тестового завдання повинен бути наданий в архіві та з детальною інструкцією щодо його розгортання. Бажано докласти Dockerfile для складання Docker контейнера для тестового завдання. Ви можете завантажити на github.com. - повинен містити коротку документацію створеного API (список запитів, параметри запитів, формати запитів, формати відповідей тощо). - Інформація про час витрачений на тестове завдання у розрізі: проектування, програмування, документація тощо. Звертаємо увагу, що це тестове завдання призначене лише для оцінки знань та умінь, а не ставить за мету створення закінченого продукту (сервера API), тому допускаються спрощення з поясненням та зазначенням причин.
уважні та досвідчені програмісти можуть пропустити наступний розділ, тут я розбиратимуся з самим текстом завдання. "Шапка" завдання не викликає жодних складнощів із сприйняттям, тому просто скажу що мій вибір припав на Spring Boot, але не тому, що я вже колись щось на ньому робив, а тому що я вже пройшов реальний проект із використанням Spring(але Boot'а там не було, як я розумію через його простоту). За функціоналом сервера: 1) Завантажувач файлів. Тут принципово нічого складного немає, мені потрібно було просто розібратися як картинки взагалі зберігаються на сервері, виявилося, що найзручнішим способом є просте розміщення їх у якійсь спеціально відведеній для цього директорії. Конкретну реалізацію розберемо нижче. 2) Додавання нового користувача, проста операція, якщо ви робабо колись CRUD програми, то він підтримає мене, якщо ні - все побачите нижче. 3) Отримання інформації про користувача. немає питань – все ясно. 4) Зміна статусу користувача. перші два пункти завдання зрозумілі як день, а що там із зовнішнім запитом? тут без 100гр не розібратися, я навіть зараз на 100% не впевнений, чи правильно я зрозумів. Деталі нижче. 5) Статистика сервера. Тут також цікаво. Першим пунктом пропонується реалізувати метод з різними варіантами параметрів, поки не зрозуміло як це робити враховуючи, що це має бути метод контролера. Другим пунктом запитують всіх користувачів, у кого змінився статус після моменту часу як відомо, але є тонкощі.
Getting Started
ох, скільки разів я читав цю фразу, поки розбирався із цим завданням! Якщо ви пробували коли-небудь розбиратися в налаштуванні проекту на Spring, але при цьому з якоїсь причини так жодного разу і не спробували Spring Boot, вітаю вас, ви відчуєте просто захоплення від того, що я напишу нижче. Я десь вичитав, що раніше програмісти дуже велику кількість коду раніше переносабо з проекту в проект, це шаблонний код - налаштування підключення до баз даних, мапінг сервлетів та інше, так щоб, наприклад, зменшити обсяг шаблонного коду для роботи з базами даних ми використовуємо JPA/Hibernate, вони приховують частину шаблонів, але щоб налаштувати їх знову ж таки потрібно писати xml файл або конфігураційні класи. а якщо у вас маленький проект, то виходить що ні фіга ви не менше за код пишете, а навіть навпаки. Далі ми обертаємо роботу з JPA в Спрінг, є багато проектів, але найбільш зручний це, звичайно ж, Spring Data. Це дуже великий проект котрий може працювати напевно з усім чим можна та JPA та NoSQL ще цілу купу різних проектів, він є неймовірно магічний ми будемо його використати у нашому проекті. Використовуючи Spring ми майже позбавляємося налаштувань з'єднання з БД, Spring все робить за нас, нам тільки потрібно наштовхувати потрібних анотацій по транзакційності, кешування і в особливих випадках нагуглити (підглянути в інших) ще якихось налаштувань у конфігурації контексту. Але при цьому у більшості розробників-початківців немає абсолютно ніякого поняття як створити проект на Spring. Ніхто не знає повністю як його налаштувати щоб запустити проект та отримати результат у браузері пройшовши за посиланням, що починається з localhost:8080/*. І тут на сцену виходить Spring Boot! Про Spring Boot краще розповісти на конкретному прикладі! Почнемо із заготівлі. Щоб створити проект Spring Boot, розробники Spring придумали "конструктор" створення шаблонів. Їм можна скористатися на їхньому сайті, але набагато простіше зробити це в нашій улюбленій IDE Intellij IDEA. І так: File->New->Project У вікні переходимо на вкладку Spring Initializr, в ній має бути виставлено jdk, та URL https://start.spring.io, перевіряємо підключення до інтернету, далі потрібно буде вибрати назву, а потім технології, які ми будемо використовувати, на першому етапі нам потрібно тільки WEB - ставимо поряд з нею галочку і далі створюється проект. Щоб мавен підтягнув всі залежності, нам потрібно відкрити вкладку Maven в ідеї і натиснути кнопку оновити. Ми отримали готовий шаблон програми, в якому зарито всі налаштування для клієнт-серверного спілкування. Щоб отримати перше враження створимо клас контролера (про MVC вже напевно всі чули). У всіх Spring додатках контролери мають досить просту конструкцію - це клас, який позначений анотацією @Controller(можливі префікси, наприклад @RestController), цей клас відповідає за обробку вхідних запитів. Для того, щоб контролер розпізнав запит на якусь адресау, потрібно зробити мапінг цієї адресаи на метод контролера. Нижче представлений код цього класу, поки ми будемо працювати без ієрархії директорій, тому покладемо його в один пакадж із класом створеним автоматично Initializr'ом, у мене він називається DemoApplication. У всіх Spring додатках контролери мають досить просту конструкцію - це клас, який позначений анотацією @Controller(можливі префікси, наприклад @RestController), цей клас відповідає за обробку вхідних запитів. Для того, щоб контролер розпізнав запит на якусь адресау, потрібно зробити мапінг цієї адресаи на метод контролера. Нижче представлений код цього класу, поки ми будемо працювати без ієрархії директорій, тому покладемо його в один пакадж із класом створеним автоматично Initializr'ом, у мене він називається DemoApplication. У всіх Spring додатках контролери мають досить просту конструкцію - це клас, який позначений анотацією @Controller(можливі префікси, наприклад @RestController), цей клас відповідає за обробку вхідних запитів. Для того, щоб контролер розпізнав запит на якусь адресау, потрібно зробити мапінг цієї адресаи на метод контролера. Нижче представлений код цього класу, поки ми будемо працювати без ієрархії директорій, тому покладемо його в один пакадж із класом створеним автоматично Initializr'ом, у мене він називається DemoApplication. щоб контролер розпізнав запит на якусь адресау потрібно зробити мапінг цієї адресаи на метод контролера. Нижче представлений код цього класу, поки ми будемо працювати без ієрархії директорій, тому покладемо його в один пакадж із класом створеним автоматично Initializr'ом, у мене він називається DemoApplication. щоб контролер розпізнав запит на якусь адресау потрібно зробити мапінг цієї адресаи на метод контролера. Нижче представлений код цього класу, поки ми будемо працювати без ієрархії директорій, тому покладемо його в один пакадж із класом створеним автоматично Initializr'ом, у мене він називається DemoApplication. import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping(value = "/hello") public class DemoController { @RequestMapping(method = RequestMethod.GET) public String halloWorld() { return "Hello World!"; } @RequestMapping(value = "/{name}", method = RequestMethod.GET) public String halloName(@PathVariable("name") String name) { return "Hello, " + name + "!"; } } Розберемося що тут. @RestController . якраз та анотація, про яку я писав вище. саме рестконтроллер використовуємо, оскільки ми хочемо відразу побачити результат і не хочемо писати сторінки.jsp (фу-яка), нам буде простіше відразу побачити результат у браузері у вигляді рядка. @RequestMapping - саме прив'язка до адресаи. префікс загальної адресаи буде таким: localhost:8080. Як бачимо весь клас висить на адресаі /helloЦе означає, що всі методи всередині цього класу мають префікс localhost:8080/hello. Далі перший метод класу, у його власному маппінгу вказаний метод Http протоколу - запит GET (про методи Http протоколу почитайте самі) Що це означає? звернувшись GET запитом на адресау localhost:8080/hello - отримаємо відповідь у вигляді рядка "Hello World!", перевіримо це! У класі DemoApplication є одна крута анотація, яка можна сказати поодинці запускає весь контекст спрингу - @SpringBootApplication. Метод main цього класу стає чарівним, якраз запускає всю магію приховану в SpringApplication, якщо викликати контекстне меню на цьому класі то в рядку Run з'являться варіанти, рекомендую запускатися рано із зеленою міткою, так консоль буде приємніше виглядати і в майбутньому буде простіше читати прямий лог з неї. Запускаємо програму. коли виведення в консоль припиниться, ви повинні побачити в консолі
2015-09-02 09:25:36.895 INFO 5844 --- [ main] sbcetTomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http) 2015-09-02 09:25:36 demo.DemoApplication : Started DemoApplication в **** seconds (JVM running for 15.501)
де "****" - тривалість запуску програми :) після цього в будь-якому браузері (або curl, або чим там ви користуєтеся?) потрібно набрати адресау на яку замапабо метод контролера
localhost:8080/hello
У браузері має відобразитися канонічне
Hello World!
ось вам та веб додаток! Якщо ви помітабо у контролері є ще один метод, там є власний мапінг адресаи, до поточної адресаи додається плейсхолдер. Який спринг передається в метод як параметр. Не важко здогадатися, що за це відповідає анотація @PathVariable. Так на запит
localhost:8080/hello/Ваше ім'я
браузер покаже
Hello, Ваше ім'я!
Із основами Spring Boot розібралися. Далі прикрутимо базу даних, але це буде вже наступного посту. Всім дякую.
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ