Друзья, всем привет.
хочу поделиться с вами опытом решения тестового задания на позицию java developer'а российской компании. Сразу скажу, реализовать основной функционал задания не представляет особой сложности, но как всегда важны детали и мелочи, которые помешали мне сдать его в срок, по заданию мне так ничего и не ответили - вакансия у них уже закрыта была когда я высылал им. Предлагаю разобраться с заданием всё ли я сделал что от меня требовалось. А тем кто понятия не имеет, как его сделать, я добавлю много воды, о том как я с ним разделывался.
Если это вдруг кому интересно - добро пожаловать под кат.
Сразу скажу, что тут всё решение я выкладывать не буду, но за-то будет много объяснений для начинающих, если кому не интересно читать мои изливания, вот вам проект на github
Начну с самого текста задания.
внимательные и опытные программисты могут пропустить следующий раздел, тут я буду разбираться с самим текстом задания. "Шапка" задания не вызывает никаких сложностей с восприятием, поэтому просто скажу что мой выбор пал на Spring Boot, но не потому что я уже когда-то что-то на нем делал, а потому что я уже прошел реальный проект с использованием Spring (но Boot'а там не было, как я понимаю из-за его простоты). По функционалу сервера: 1) Загрузчик файлов. Тут принципиально ничего сложного нет, мне нужно было просто разобраться как картинки вообще хранятся на сервере, оказалось, что наиболее удобным способом является простое размещение их в какой-нибудь специально отведенной для этого директории. Конкретную реализацию разберем ниже. 2) Добавление нового пользователя, простая операция, если вы делали когда-нибудь CRUD приложения, то он поддержит меня, если нет - всё увидите ниже. 3)Получение информации о пользователе. нет вопросов - всё ясно. 4)Изменение статуса пользователя. первые два пункта задания ясны как день, а что там с внешним запросом??? тут без 100гр не разобраться, я даже сейчас на 100% не уверен правильно ли я понял. Детали ниже. 5)Статистика сервера. Тут тоже интересно. первым пунктом предлагается реализовать метод с различными вариантами параметров, пока не понятно как это делать учитывая что это должен быть метод контроллера. вторым пунктом спрашивают всех юзеров, у кого изменился статус после момента времени вроде понятно, но есть тонкости.
Тестовое задание №1
Описание: Сервер API (JSON HTTP API) Средства разработки: Java Framework: Play Framework 2.4 (или выше) или Spring boot 1.2.3 (или выше) База данных: MySQL Протокол: HTTP, порт 80 Функционал (запросы):- Загрузчик.
- Передаем на сервер файл (картинка аватара JPG).
- Сохраняем картинку в каталоге на сервере.
- Ответ сервера - внутренний URI картинки.
- Добавление нового пользователя.
- Передаем на сервер персональные данные пользователя (URI картинки, имя пользователя, email и т.д.).
- Сохраняем информацию в базе данных.
- Ответ сервера - уникальный ID нового пользователя.
- Получение информации о пользователе.
- Передаем на сервер уникальный ID пользователя.
- Читаем информацию из базы данных.
- Ответ сервера - персональные данные пользователя (см. выше).
- Изменение статуса пользователя (Online, Offline).
- Передаем на сервер уникальный ID пользователя и новый статус (Online, Offline).
- Изменяем статус пользователя.
- Ответ сервера - уникальный ID пользователя, новый и предыдущий статус.
- Статистика сервера.
- Передаем параметры на сервер: 1. статус клиентов (Online, Offline или отсутствует), 2. уникальный ID (timestamp) запроса (может отсутствовать)
- Ответ сервера - список пользователей со статусами и URI картинки, а также уникальный 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.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] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http) 2015-09-02 09:25:36.900 INFO 5844 --- [ main] demo.DemoApplication : Started DemoApplication in **** seconds (JVM running for 15.501)где "****" - длительность запуска приложения :) после этого в любом браузере (или curl, или чем там вы пользуетесь?) нужно набрать адрес на который замапили метод контроллера
localhost:8080/helloВ браузере должно отобразиться каноническое
Hello World!вот вам и веб приложение! Если вы заметили в контроллере есть еще один метод, там есть собственный маппинг адреса, к текущему адресу добавляется плейсхолдер. Который спрингом передается в метод в качестве параметра. Не трудно догадаться что за это отвечает аннотация @PathVariable. Так на запрос
localhost:8080/hello/Ваше имябраузер покажет
Hello, Ваше имя!С основами Spring Boot разобрались. Далее прикрутим базу данных, но это будет уже в следующем посте. Всем спасибо.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Это такой тонкий референс к «неточным» формулировкам задач на javarush
ps не единственный)