Skip to content

Oberonru/Thumbtack

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

51 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Заочная Школа разработчика

Алексей Петрушенко
oberonru@mail.ru
Омск, ОмГТУ, Машиностроительный институт, 2007 г.

Концерт по заявкам

  1. Введение

Радиостанция “Белые паруса” решила провести концерт по заявкам радиослушателей. Программа концерта должна включать в себя самые популярные, по мнению радиослушателей, песни. Для оценки популярности песен и формирования программы концерта было решено создать сервер, на котором слушатели могли бы предлагать те или иные песни в программу концерта и давать свои оценки. По результатам этих предложений и оценок будет сформирована программа.

Руководство радиостанции обратилась к Вам с просьбой разработать такой сервер.

Руководство радиостанции предполагает, что высказанные им требования к правилам формирования программы концерта и оценке песен являются логичными и непротиворечивыми. Так ли это в действительности или нет - должно выясниться в процессе разработки и пробной эксплуатации сервера. Если в ходе разработки появится необходимость корректировки тех или иных пунктов задания, то этот вопрос должен обсуждаться совместно представителями радиостанции и разработчика с внесением в случае необходимости изменений в техническое задание. Не исключено, что по результатам пробной эксплуатации появится необходимость внесения каких-то дополнений в техническое задание.

Вам предстоит разработать версию сервера, в которой все его данные должны храниться в оперативной памяти. Должна быть предусмотрена возможность сохранить состояние сервера в файл и загрузить это состояние из файла.

  1. Описание системы

Радиослушатели, желающие принять участие в составлении программы концерта, должны зарегистрироваться на сервере. При регистрации они указывают фамилию имя логин и пароль для входа на сервер. Введенные при регистрации данные изменению в дальнейшем не подлежат. Радиослушатели не могут регистрироваться два или более раза на сервере. Зарегистрированный на сервере радиослушатель может выйти с сервера. Вышедший с сервера радиослушатель может войти на сервер снова. При этом ему достаточно ввести свои логин и пароль. Зарегистрированный на сервере радиослушатель может покинуть сервер, в этом случае вся информация о нем удаляется, а список сделанных им предложений обрабатывается как указано ниже. Любой радиослушатель может предложить любое количество песен в программу концерта. При этом он не обязан предложить все песни сразу, а может добавлять их по одной или сразу несколько. Для каждой песни он должен указать название песни композитора автора слов исполнителя (фамилия или название группы) продолжительность песни в секундах Некоторые песни могут иметь более одного композитора или автора слов. в этом случае слушатель вправе указать всех или только некоторых. Исполнитель у песни всегда один. Радиослушатель, предложивший песню в состав концерта, считается автором этого предложения. Радиослушатели могут ставить свои оценки предлагаемым в программу песням по шкале 1..5. Радиослушатели вправе изменить свою оценку или вообще удалить ее в любое время. Автор предложения автоматически оценивает свое предложение оценкой “5” и не вправе ни изменить, ни удалить свою оценку. Радиослушатели, сделавшие свое предложение, могут отменить его. Если на момент отмены предложение не получило никаких оценок от других радиослушателей, оно удаляется. Если же к этому моменту имеются другие оценки этого предложения, то удаляется лишь оценка этого предложения, сделанная автором предложения (то есть его оценка 5), а само предложение не удаляется, все остальные оценки сохраняются, а автором предложения считается сообщество радиослушателей. Если радиослушатель покидает сервер, считается, что он отменяет все свои предложения по этому же механизму. Радиослушатели могут добавлять свои комментарии к предложениям. Комментарий представляет собой одну текстовую строку. Радиослушатель, сделавший комментарий, считается его автором. Радиослушатели могут присоединяться к комментариям, сделанным ранее другими радиослушателями. Автор комментария вправе изменить его в любой момент. Если на момент изменения к этому комментарию еще никто не присоединился, старый текст комментария просто заменяется на новый. Если же к этому комментарию кто-то успел к моменту его изменения автором комментария присоединиться, старый вариант комментария остается без изменений, новый вариант добавляется к списку комментариев для этой песни, а автором старого комментария считается сообщество радиослушателей. Если радиослушатель покидает сервер, то этот механизм применяется ко всем его комментариям, в том числе и тем, к которым никто не присоединился. Радиослушатели, присоединившиеся к комментарию, вправе отказаться от своего присоединения, но не могут изменять текст комментария.

В любой момент любой радиослушатель может получить следующие списки

Все заявленные в концерт песни. Все заявленные в концерт песни указанного композитора или композиторов. Все заявленные в концерт песни указанного автора слов или авторов слов. Все заявленные в концерт песни указанного исполнителя.

В любой момент любой радиослушатель может получить текущую пробную программу концерта. Пробная программа - это концерт из песен, набравших наибольшие суммы оценок при условии, что суммарная продолжительность концерта не превышает 60 минут с учетом того, что между каждыми двумя песнями делается пауза продолжительностью в 10 секунд. В случае, если очередная песня из списка наиболее популярных не может быть добавлена в концерт, потому что при этом будет превышено время концерта, эта песня пропускается, и делается попытка добавить следующую по популярности песню и т.д.  В концерт должно включаться максимально возможное количество песен. В пробную программу концерта для каждой песни включаются

Название песни, композитор(ы), автор(ы) слов, исполнитель Данные о радиослушателе, предложившем песню. Средняя оценка песни. Все комментарии к этому предложению.

Задание 11.

Правила выполнения Задания

Задание 11 - большое, и рассчитано не на один день Вашей работы. При выполнении его нужно соблюдать следующие правила :

Для того, чтобы не потерять результаты своей работы, рекомендуется делать промежуточные коммиты на сервер (git push) по мере выполнения той или иной части. Как минимум, рекомендуется делать коммиты по окончании каждого рабочего дня. Не разрешается делать коммиты, в которых код не компилируется или не работают все тесты. Если Вы не успеваете в этот день исправить все ошибки - просто закомментируйте тот код, который не компилируется или не работает. Для тестов можно использовать аннотацию @Ignore (помещается перед аннотацией @Test), при ее наличии тест не будет запускаться. Преподаватели не будут просматривать коммиты после каждой посылки на сервер. Если Вы хотите, чтобы преподаватель просмотрел состояние Вашей работы и сделал свои замечания - напишите ему об этом в Скайпе или по email после того, как сделали коммит и дождитесь его ответа, прежде чем вносить изменения на сервере. Обсуждать Задание 11 разрешается только со своим преподавателем. Обсуждать Задание 11 (и даже упоминать о том, что Вы приступили к нему) в основном чате Школы, в группе Вконтакте и с другими студентами не разрешается!

В этом задании Вам все предстоит сделать самим - разработать набор классов, написать код и тесты к нему.
Внимательно прочтите техническое задание (https://docs.google.com/document/d/1L3FISiFz0nmSUsP5-eUR6fK8kr0wjdKGUNjJGV6A9yc/edit#)

Все классы предыдущих заданий можно удалить или, как минимум, удалить все тесты.
Создайте пакет net.thumbtack.school.concert в каталогах main и test. В каталоге main в этом пакете размещайте Ваши классы, а в каталоге test - тесты для них.

Вы можете создавать в пакете net.thumbtack.school.concert любые подпакеты любой степени вложенности и классы в них. Более того, настоятельно рекомендуется создавать такие подпакеты, а не хранить все классы в основном пакете. Имена классов тестов должны начинаться с “Test”.

Создайте в пакете net.thumbtack.school.concert подпакет server. Разместите в этом пакете класс Server.  В этом классе должны быть методы

public void startServer(String savedDataFileName)

Производит всю необходимую инициализацию и запускает сервер.

savedDataFileName - имя файла, в котором было сохранено состояние сервера. Если savedDataFileName == null, восстановление состояния не производится, сервер стартует “с нуля”.

public void stopServer(String savedDataFileName)

Останавливает сервер и записывает все его содержимое в файл сохранения с именем savedDataFileName. Если savedDataFileName == null, запись содержимого не производится.

После того, как сервер запущен (выполнен метод startServer), ему можно посылать команды. Команда представляет собой вызов одного из методов класса Server. Команды выполняются последовательно, до тех пор пока не будет вызван метод stopServer, по выполнении которого работа сервера заканчивается.

Все методы должны иметь одну и ту же сигнатуру.

public String <имя-метода>(String requestJsonString)

Все данные для запроса должны быть упакованы в json-строку и в таком виде переданы методу. Метод возвращает json-строку с результатом выполнения операции.

При регистрации (метод registerUser) радиослушателя возвращаемая строка (при успешном выполнении) должна обязательно содержать поле “token” - уникальный номер, присвоенный этому радиослушателю в результате регистрации. Токен - некоторая текстовая строка, к которой предъявляется следующее требование : при каждом получении токена должна выдаваться строка, отличная от всех предыдущих. Иными словами, все токены должны быть различными. Для генерации таких строк рекомендуется использовать класс UUID (https://docs.oracle.com/javase/8/docs/api/java/util/UUID.html). Этот класс позволяет при каждом вызове метода randomUUID получать уникальное во всем мире значение, которое можно преобразовать в строку с помощью метода toString. Это токен является “визитной карточкой” радиослушателя. Все остальные команды, выполняемые от имени этого радиослушателя, должны содержать поле “token” во входной json-строке - параметре метода, тем самым указывая, от чьего имени выполняется команда. Логин и пароль в этих командах задавать не надо. Если радиослушатель выполняет операцию выхода (метод logout) с сервера, его токен впредь считается недействительным (невалидным). При попытке выполнить любой метод с предъявлением этого токена должен возвращаться json с ошибкой. Если радиослушатель, вышедший с сервера, входит на него снова (метод login), он получает новый токен, который может использовать во всех операциях вплоть до нового выхода.

В случае успешного выполнения возвращаемая строка содержит (в формате json) требуемые по условиям команды возвращаемые данные.

Если команда содержит неверные данные (например, при регистрации не указан логин или пароль) или не может быть выполнена по какой-то иной причине (например, пользователь с таким логином уже зарегистрирован), метод сервера должен возвращать json, содержащий поле “error”, описывающее характер ошибки в виде, понятном для человека (например, “Этот логин уже используется” или “Логин abcdef уже используется”). Разрешается добавить в этот json иные поля, если разработчик считает это необходимым. Вы должны самостоятельно сформулировать требования к входным данным параметров команд в том случае, когда это имеет смысл. Например, естественным будет требование, чтобы в качестве логина и пароля не использовалась пустая строка, и, более того, строка длины, меньше минимально допустимой. Для пароля можно сформулировать и более жесткие требования, например, потребовать наличия хотя бы одного спецсимвола. Не должно быть двух пользователей с одним и тем же логином и т.д.

Примеры команд

public String registerUser(String requestJsonString)

Регистрирует радиослушателя на сервере. requestJsonString содержит данные о радиослушателе, необходимые для регистрации. Метод при успешном выполнении возвращает json с единственным элементом “token”. Если же команду по какой-то причине выполнить нельзя, возвращает json с элементом “error”

public String addSong(String requestJsonString)

Радиослушатель добавляет новую песню на сервер. requestJsonString содержит описание песни и token, полученный как результат выполнения команды регистрации радиослушателя. Метод при успешном выполнении возвращает пустой json . Если же команду почему-то выполнить нельзя, возвращает json с элементом “error”

public String getSongs(String requestJsonString)

Радиослушатель получает список песен. requestJsonString содержит параметры для отбора песен и token, полученный как результат выполнения команды регистрации радиослушателя. Метод при успешном выполнении возвращает json с описанием всех песен. Если же команду почему-то выполнить нельзя, возвращает json с элементом “error”

Покрытие тестами

Разрабатывая те или иные методы классов, не забывайте писать для них тесты. В наборе тестов должны быть такие, которые проверяют правильность выполнения команд при корректных и  некорректных входных данных. Например, должны быть тесты для регистрации радиослушателя с корректными данными, с недопустимым логином и/или паролем, с уже существующим в системе логином, или, например, тесты, проверяющие попытку доступа с несуществующим токеном и т.д. Для оценки, насколько код покрыт тестами, используйте Coverage.

Все задание должно быть оформлено в виде набора тестов, вызывающих методы класса Server. Например:

@Test public void testRegisterUser { Server server = new Server(); server.startServer(null); String jsonRequest = “json-для-регистрации-радиослушателя”; String jsonResponse = server.registerUser(jsonRequest); // assert’ы для jsonResponse server.stopServer(null); }

Не обязательно писать все тесты в одном классе тестов, более того, настоятельно рекомендуется иметь несколько классов тестов в соответствии с их назначением.

3d party библиотеки

При разработке разрешается использовать библиотеки, не входящие в стандартную библиотеку Java. Подключать такие библиотеки следует через pom.xml. В частности, рекомендуется ознакомиться с библиотекой Apache Common Collections (https://commons.apache.org/proper/commons-collections/) и использовать ее классы.

Задание 11 достаточно сложное, поэтому при написании его следует проработать архитектуру приложения.

Итак, мы должны сделать класс Server, в котором будет N методов, каждый из которых принимает строку в формате json и возвращает строку, тоже в формате json. Конечно, можно реализовать все эти методы непосредственно в самом классе Server, но при этом размер его будет огромным, а код будет очень трудно понять. Поэтому лучше разбить задачу на части. Эти части достаточно очевидны - операции для регистрации и логина радиослушателя, по добавлению песен, написанию комментариев, возможно, другие. Будет лучше, если класс Server сам никакие операции выполнять не будет, а будет делегировать их выполнение соответствующему классу, который мы назовем классом сервиса (например, UserService, SongService и т.д), вызывая соответствующий метод из этого класса. Экземпляры этих классов должны быть полями класса Server. Итак, класс Server передает полученный json соответствующему классу сервиса. Этот класс должен распарсить json, проанализировать и проверить находящийся в нем запрос, выполнить его (конечно, если в запросе нет ошибок) и вернуть ответ. Если в запросе имеются ошибки, класс сервиса должен тут же вернуть ответ с полем “error”, не производя дальнейшей обработки. Класс сервиса получил запрос в формате json. Можно, конечно, попробовать “вытащить” каждое поле из этого json по отдельности и проанализировать его, но лучше преобразовать этот json в экземпляр специального класса, который содержит те же поля, что и исходный json. Этот класс мы назовем классом DTO (data transfer object). Получить экземпляр этого класса можно из исходного json простым вызовом gson.fromJson(jsonString, Class classDTO).

Например

Пусть мы имеем некий запрос на регистрацию радиослушателя, в котором через json передаются 4 полей - фамилия, имя, логин и пароль. В этом случае класс DTO будет содержать эти же 3 поля и иметь вид

class RegisterUserDtoRequest { private String firstName; private String lastName; private String login; private String password; // конструкторы, геттеры и сеттеры }

Тогда преобразование из json-строки в экземпляр этого класса выглядит так

RegisterUserDtoRequest registerUserDtoReques = gson.fromJson(jsonString,RegisterUserDtoRequest.class);

Итак, мы преобразовали исходную json строку в экземпляр класса. Теперь самое время проверить этот запрос. Правильно ли заданы firstName и lastName, не являются ли они пустыми, не является ли пустым пароль, и если нет - удовлетворяет ли пароль каким-то требованиям и т.д. В случае обнаружения ошибки при анализе класс сервиса прекращает дальнейшую обработку и возвращает json с полем “error”. Такую проверку может провести сам сервис, проверяя каждое поле. Альтернативный вариант - сделать в классе RegisterUserDtoRequest метод validate и перенести все проверки в него, а сервис пусть вызывает этот метод. Если ошибок в запросе не было, значит, запрос должен быть передан на дальнейшую обработку. Теперь надо из экземпляра класса запроса (класса DTO) создать экземпляр класса модели, в данном случае класса User. Это класс в данном случае будет содержать те же 4 поля, то есть иметь вид

class User { private String firstName; private String lastName; private String login; private String password; // конструкторы, геттеры и сеттеры }

Вопрос - зачем иметь 2 разных класса, если они фактически содержат одно и то же ? В данном случае возникает впечатление, что действительно незачем. Однако, если вдуматься, то можно понять, что запрос на создание чего-то и то, что на основе этого запроса должно быть создано - это далеко не всегда одно и то же. Например, возможна ситуация, когда в запросе могут отсутствовать некоторые поля, а в классе модели они должны присутствовать. Если бы класс User содержал внутри дату и время создания этого User, то в запросе эти данные, скорее всего , не приводились бы , потому что текущие дату и время можно всегда легко получить перед созданием User. Более того, возможны ситуации, когда запрос на создание радикально отличается по формату от того, что нужно создать. Например, запрос мог бы содержать начальную и конечную дату какого-то интервала дней, а создать надо список дней, входящих в этот интервал. Поэтому лучше иметь отдельно класс запроса и класс модели, который создается по этому запросу.

Итак, мы создали экземпляр класса модели. В этом экземпляре данные корректные в соответствии с нашими требованиям, так как мы создавали его только в том случае, если экземпляр класса запроса прошел проверку.

Экземпляр класса модели мы теперь должны добавить в нашу базу данных. Для этого создадим еще один класс - класс DAO (data access object) и поручим ему эту работу. Аналогично тому, как в самом начале класс Server перепоручил работу классу сервиса, класс сервиса теперь перепоручает работу классу DAO. Назовем этот класс UserDaoImpl (от слова implementation)

Зачем нужен новый класс ? Почему не выполнить всю работу по вставке экземпляров классов модели в базу в самом сервисе ? Сервис занят логикой операции - он проверяет входные данные, создает экземпляр класса модели, возможно, производит какие-то иные действия, возвращает результат. Для работы с базой данных сервис использует класс DAO, который только и знает, как работать с базой данных, сервис об этом не знает и знать не должен - не его дело. Если со временем мы решим использовать иную базу данных, нам придется переписать класс DAO, а класс сервиса останется без изменений вообще. Кроме класса DAO, целесообразно сделать интерфейс к этому классу. Интерфейс объявляет методы, которые класс должен имплементировать. Если мы решим использовать иную базу данных, то класс DAO придется переписать, а интерфейс - нет, так как они лишь определяет набор действий и ничего не говорит о том, как они будет реализованы.

Например:

Из класса DTO мы создали экземпляр класса User, и теперь хотим его добавить в базу данных.

interface UserDao { void insert(User user); }

class UserDaoImpl implements UserDao { void insert(User user) { // здесь код добавления в базу данных }

Разумеется, тип void в качестве типа результата метода здесь выбран лишь для примера, вполне возможно, что нужно будет использовать другой тип.

Что должен содержать код добавления в базу данных - зависит от того, какая база данных у нас используется. Например, если в качестве базы данных используется SQL сервер, то метод insert должен выполнять операцию SQL INSERT, если иную промышленную базу данных (например, какую-то NoSQL БД), то должны использоваться ее соответствующие средства и т.д. В нашем задании “базу данных” Вам предстоит сделать самим. Конечно, это не будет настоящая база данных, а всего лишь набор каких-то классов коллекций (List, Set, Map и т.д.), который в совокупности позволяет хранить все требуемые данные и вести поиск по ним. Поэтому создадим еще один класс - DataBase. Экземпляр этого класса у нас будет один-единственный - это же база данных, а она у нас одна. В этом классе и разместим все свои коллекции. Кстати, именно этот экземпляр класса надо сохранять в файл при окончании работы сервера и загружать из файла при старте сервера, потому что только он и содержит все данные о радиослушателях, песнях и т.д. Классы DTO, DAO и сервисов никаких хранимых в БД данных не содержат, они используются только для выполнения действий, а не для хранения состояния, поэтому сохранять их в файл не имеет смысла.

Для нашей имплементации DAO метод DAO просто делегирует исполнение аналогичному методу из класса DataBase

class UserDaoImpl implements UserDao { void insert(User user) { database.insert(user); }

а тот и производит вставку/изменение/удаление/поиск в своих коллекциях.

Теперь давайте обсудим возврат результата. Отметим, что возвращаемый результат может быть как очень простым, так и очень сложным. Например, при регистрации радиослушателя возвращается json с единственным полем - “token”, а при формировании пробного концерта возвращается достаточно сложный ответ, содержащий в себе один или несколько списков.

Последовательность действий для возврата результата та же, что и при обработке запроса, только в обратном направлении. После того, как метод класса DataBase произвел операцию с базой данных, он возвращает какой-то результат классу DAO, тот, в свою очередь, передает его классу сервиса, а класс сервиса на основании этого результата создает класс DTO, но теперь уже не DTO запроса, а DTO ответа. В этом DTO ответа должны быть те поля, которые и предполагается вернуть в качестве результата метода. Например, в классе RegisterUserDtoResponse вполне может быть одно лишь поле “token”, а в классе GetSongsDtoResponse должен быть список из песен и иная требуемая информация.

Вышеупомянутые классы и интерфейсы следует разместить в своих пакетах. Например, для DAO - интерфейсов нужно создать пакет net.thumbtack.school.concert.dao, для их имплементаций - net.thumbtack.school.concert.daoimpl, для сервисов - net.thumbtack.school.concert.service, для DTO - net.thumbtack.school.concert.dto.request и net.thumbtack.school.concert.dto.response и т.д.

Обработка ошибок

Ошибки, обнаруженные на этапе парсинга и проверки входного json, обнаруживает сервис, и он же формирует ответ с полем “error” в этом случае. Однако ошибки могут возникать и при работе методов классов DAO или класса DataBase. Например, приходит новый запрос на регистрацию User. Запрос проверяется сервисом, признается корректным, передается DAO и далее DataBase, а класс DataBase обнаруживает, что радиослушатель с таким логином уже зарегистрирован. Таким образом, хотя синтаксически запрос корректен, выполнить его все же невозможно. Обнаружив такую ошибку, класс DAO (или DataBase) выбрасывает исключение, внутри которого имеется код ошибки и/или строка, описывающая эту ошибку. Это исключение перехватывает класс сервиса, который и формирует ответ с полем “error” в этом случае

Работа сервера и тестирование

Для того, чтобы запустить сервер, нужно, конечно, написать метод main, в котором (или в вызываемых им методах) пользователь в той или иной форме вводит запрос с консоли, после чего сервер этот запрос выполняет, затем с консоли вводится следующий запрос и т.д. Однако в нашем задании мы метод main писать не будем и ввод с консоли тоже. Для проверки работы методов сервера мы будем использовать junit-тесты.

Например, пусть у нас есть метод

String registerUser(String json)

В этом случае соответствующий тест может выглядеть примерно так

@Test public void testRegisterUser() { RegisterUserDtoRequest request = new RegisterUserDtoRequest(параметры); String jsonRequst = gson.toJson(request); String jsonResponse = registerUser(String jsonRequest); RegisterUserDtoResponse response = gson.fromJson(jsonResponse, RegisterUserDtoResponse.class); // необходимое количество assertXYZ, проверяющих результат

}

Разумеется, надо написать и такие тесты, в которых на вход метода передаются некорректные данные (отсутствует имя, слишком короткий пароль и т.д.). В этом случае в строке json ответа должно быть поле “error” с адекватной диагностикой, и следует проверить, верно ли диагностирована ошибка.

Простейшие (unit) тесты проверяют лишь отдельные действия. Более сложные (интеграционные) тесты могут представлять собой целый сценарий - например, регистрацию нескольких радиослушателей, добавление песен и комментариев к ним, формирование программы и т.д.

Примерная структура проекта (для модели водитель - автомобиль)

| | --- Server.java | --- service | --- UserService.java | --- CarService.java | --- model | --- User.java | --- Car.java | --- dao | --- UserDao.java | --- CarDao.java | --- daoimpl | --- UserDaoImpl.java | --- CarDaoImpl.java | --- database | --- Database.java | --- dto.request | --- LoginDtoRequest.java | --- RegisterUserDtoRequest.java | --- AddCarDtoRequest.java | --- dto.response | --- LoginDtoResponse..java | --- RegisterUserDtoResponse.java | --- AddCarDtoResponse.java

Структуру проекта можно изменять, но рекомендуется придерживаться представленной выше. В реальных проектах она выглядит именно таким образом.

Описание пакетов и классов проекта

Database - класс, содержит в себе все необходимые структуры данных , то есть различные коллекции (Map, Set, List и т.д.) классов моделей. Для реализации данного класса следует использовать паттерн Singleton (https://refactoring.guru/ru/design-patterns/singleton/java/example) Server - класс, принимающий запросы (вызовы методов данного класса). В данном классе определены все сервисы. Запросы приходят в методы класса Server в виде json- строки. Сервер возвращает ответ также в виде json-строки. dto - пакет с классами, описывающими запросы и ответы. Например, если для входа на сервер нужны только логин и пароль из модели User, то необходимо создать класс LoginDtoRequest с двумя полями - “login и “password” для запроса и класс LoginDtoResponse с полем “token” для ответа. service - пакет с классами, в которых производятся получение строки запроса от Server, преобразование json в соответствующий класс dto-запрос, проверка этого dto (валидация), арифметические операции, создание экземпляров классов модели на основе этого dto или получение экземпляров классов модели на основе dto-запроса и другие действия бизнес-логики. Для записи экземпляров модели в базу данных или для получения их из базы данных сервис вызывает dao. Сервис возвращает ответ серверу в виде текстовой строки в формате json, создавая для этого экземпляр класса dto-ответ и преобразуя его в json. dao - пакет (см. https://www.codeflow.site/ru/article/java-dao-pattern только 1 и 2 пункты). Связь с базой данных (классом Database) осуществляется именно dao классами. daoimpl - пакет с имплементациями dao-интерфейсов. model - пакет с классами описывающими объекты приложения. Например, для пользователя можно создать класс модели User. Классы модели должны быть максимально простыми, содержать поля и методы для получения и переопределения этих полей (геттеры и сеттеры). Классы модели не должны содержать методов, выполняющих какие-то действия (запись в файл, в базу данных и т.д.) - этим должны заниматься методы класса сервиса с помощью DAO

Поток данных

Данные в нашем приложении должны передаваться следующим образом:

Вызов метода сервера из теста -> метод Server -> метод Service -> метод Dao -> метод Database. Любой метод может возвращать какой-то результат, если это необходимо для того, чтобы сформировать ответ. Любой метод может выбросить исключение, если выполнение операции невозможно по какой-то причине. Исключения обрабатывает класс сервиса, инициировавший операцию.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages