Занятие №11

Курсовой проект

Михаил

Павлов

Что мы уже узнали

  1. Как начать свой проект
  2. Основы ООП в Java
  3. Обобщения и коллекции
  4. Функциональное программирование в Java
  5. Работа с файловой системой
  6. Spring Core
  7. Spring Boot
  8. Rest API
  9. JPA и Hibernate
  10. Spring Data
  11. Тесты

Для применения этих знаний нужен проект

Вспомним, что мы делали раньше

(на 8 занятии)

Задача:

Сделать веб-приложение со списком вопросов

Требования:

  • Отображать список вопросов
  • Поиск вопросов по подстроке
  • Фильтрация по количеству доступных ответов (*)
  • Постраничная навигация (*)

(*) - Опционально

Сделано

Следующее задание

Задача:

Доработать веб-приложение

Требования:

  • Создание и редактирование вопроса (со списком ответов)
  • Фильтрация по количеству доступных ответов (*)
  • Постраничная навигация (*)

(*) - Опционально

Давайте применим всё, что мы узнали

Что мы сделаем сегодня

  1. Хранение сущности журнала в БД (Entity)
  2. Получение её на клиенте (Repository, Service, RestService)
  3. Хранение сущностей вопросов и ответов в БД
  4. Получение списка строк журнала вопросов
  5. Создание нового вопроса с ответами

Схема данных

Как подключиться к базе данных (на примере H2)

Зависимости:

dependencies {
  implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
  runtimeOnly 'com.h2database:h2'
}

Настройки:

spring.datasource.url=jdbc:h2:mem:restapp;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
spring.h2.console.enabled=true
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

Имя своей БД

Практика

  • Скачать и установить nodeJS
  • Выкачать репозиторий по ссылке (папка unit-12)
  • Перед первым запуском клиента выполнить команду
    • npm i
  • Запускаем клиент через консоль в папке app-client
    • npm start
  • Запускаем сервер через консоль в папке app-server  (или через Идею)
    • gradlew bootRun

Как работает клиент

Практика

Http-запросы:

  • Получение метаданных журнала

  • Получение строк журнала

  • Создание вопроса

  • Редактирование вопроса

  • Получение списка вопросов для новой сессии

  • Сохранение новой сессии

Клиент ожидает сервер по адресу http://localhost:8080

Практика

Клиент ожидает данные по двум журналам:

- Вопросы (id = questions)

- Сессии (id = sessions)

Получение метаданных журнала

Тип метода: GET

URL: http://localhost:8080/api/journal/<строка с id журнала>

Пример: http://localhost:8080/api/journal/questions

Ожидаемый ответ:

Пример ответа (JSON):

{
  id: string;
  name: string;
  defaultPageSize?: number;
}
{ 
  "id": "questions",
  "name": "Вопросы",
  "defaultPageSize": 15 
}

Получение строк журнала (вопросы)

Тип метода: PUT

URL: http://localhost:8080/api/journal/<строка с id журнала>/rows

Пример: http://localhost:8080/api/journal/questions/rows

Тело запроса:

Пример тела запроса (JSON):

{ journalId: string;
  search: string;
  filters: JournalFilterItem[];
  page: number;
  pageSize: number; }
{ type: string;
  code: string;
  value: string; }

JournalFilterItem:

{ "journalId": "questions",
  "search": "someText",
  "filters": [{
    "code": "question-answer-count",
    "type": "single-select",
    "value": 2
  }],
  "page": 1,
  "pageSize": 15 }

Получение строк журнала (вопросы)

Ожидаемые ответ:

Пример тела ответа (JSON):

{
  total: number;
  items:
  [{ 
    id: string;
    name: string;
    answers: AnswerItemDTO[]; 
  }]
}
{
  "total" : 2,
  "items":
  [{ 
    "id": 1,
    "name": "Вопрос 1",
    "answers": [{
      "id": 3,
      "answerText": "Ответ 3",
      "isCorrect": true
    }]
  }, {
    "id": 2,
    "name": "Вопрос 2",
    "answers": [{
      "id": 4,
      "answerText": "Ответ 4",
      "isCorrect": false
    }]
  }] 
}
{ id: string;
  answerText: string;
  isCorrect: boolean; }

AnswerItemDTO:

Получение строк журнала (сессии)

Тип метода: PUT

URL: http://localhost:8080/api/journal/<строка с id журнала>/rows

Пример: http://localhost:8080/api/journal/sessions/rows

Тело запроса:

Пример тела запроса (JSON):

{ journalId: string;
  search: string;
  filters: JournalFilterItem[];
  page: number;
  pageSize: number; }
{ type: string;
  code: string;
  value: string; }

JournalFilterItem:

{ "journalId": "sessions",
  "search": "someText",
  "filters": [],
  "page": 1,
  "pageSize": 15 }

Получение строк журнала (сессии)

Ожидаемые ответ:

Пример тела ответа (JSON):

{
  total: number;
  items:
  [{ 
    id: string;
    name: string;
    insertDate: Date; 
    result: number;
  }]
}
{
  "total" : 2,
  "items":
  [{ 
    "id": 1,
    "name": "Иванов И.И.",
    "insertDate": 1568073600,
    "result": 80
  }, {
    "id": 2,
    "name": "Сидоров А.А.",
    "insertDate": 1568073600,
    "result": 100
  }] 
}

Создание вопроса

Тип метода: POST

URL: http://localhost:8080/api/question/create

Пример: http://localhost:8080/api/question/create

Тело запроса:

Пример тела запроса (JSON):

{
  name: string;
  answers: AnswerItemDTO[];
}
{ answerText: string;
  isCorrect: boolean; }

AnswerItemDTO:

{
  "name": "Текст вопроса",
  "answers": [{
    "answerText": "Текст ответа",
    "isCorrect": true
    }]
}

Создание вопроса

Тело ответа:

Пример тела запроса (JSON):

{
  id: string;
  name: string;
  answers: AnswerItemDTO[];
}
{ 
  id: string;
  answerText: string;
  isCorrect: boolean; 
}

AnswerItemDTO:

{
  "id": "1",
  "name": "Текст вопроса",
  "answers": [{
    "id": "2",
    "answerText": "Текст ответа",
    "isCorrect": true
    }]
}

Редактирование вопроса

Тип метода: PUT

URL: http://localhost:8080/api/question/edit

Пример: http://localhost:8080/api/question/edit

Тело запроса:

Пример тела запроса (JSON):

{
  id: string;
  name: string;
  answers: AnswerItemDTO[];
}
{ answerText: string;
  isCorrect: boolean; }

AnswerItemDTO:

{
  "id": "1",
  "name": "Текст вопроса",
  "answers": [{
    "answerText": "Текст ответа",
    "isCorrect": true
    }]
}

Редактирование вопроса

Тело ответа:

Пример тела запроса (JSON):

{
  id: string;
  name: string;
  answers: AnswerItemDTO[];
}
{ 
  id: string;
  answerText: string;
  isCorrect: boolean; 
}

AnswerItemDTO:

{
  "id": "1",
  "name": "Текст вопроса",
  "answers": [{
    "id": "2",
    "answerText": "Текст ответа",
    "isCorrect": true
    }]
}

* ответ такой же как при создании вопроса

Список вопросов для новой сессии

Тип метода: GET

URL: http://localhost:8080/api/session/questions-new

Пример: http://localhost:8080/api/session/questions-new

Ответ (список):

[{
  id: string;
  name: string;
  answers: AnswerItemDTO[];
}]
{ 
  id: string;
  answerText: string;
  isCorrect: boolean;
}

AnswerItemDTO:

Поле "isCorrect" есть в AnswerItemDTO, но лучше его не слать с сервера :)

Пример ответа (JSON):

[{
  "id": "1",
  "name": "Текст вопроса",
  "answers": [{
    "id": "3",
    "answerText": "Текст ответа"
    }]
}, {
  "id": "2",
  "name": "Текст вопроса2",
  "answers": [{
    "id": "4",
    "answerText": "Текст ответа2"
    }]
}]

Список вопросов для новой сессии

Создание новой сессии

Тип метода: POST

URL: http://localhost:8080/api/session

Пример: http://localhost:8080/api/session

Тело запроса:

{
  name: string;
  questionsList: AnsweredQuestionDTO[];
}
{ id: string;
  answersList: SessionQuestionAnswer[]; }

AnsweredQuestionDTO:

Создание новой сессии

{ id: string;
  isSelected: boolean; }

SessionQuestionAnswer:

Пример тела запроса (JSON):

{
  "name": "Иванов Иван Иванович",
  "questionsList": [{
    "id": "1",
    "answersList": [{
      "id": "2",
      "isSelected": true
  	}]
  }, {
    "id": "3",
    "answersList": [{
      "id": "4",
      "isSelected": true
    }, {
      "id": "5",
      "isSelected": false
  	}]
  }]
}

Создание новой сессии

Создание новой сессии

В ответ получаем строку - количество набранных процентов

Как посмотреть, что летит с клиента и обратно

(в Google Chrome)

1. Зайти в инструменты разработчика в браузере

Варианты, как это можно сделать:

  • Кнопка с троеточием -> Дополнительные инструменты -> Инструменты разработчика
  • Ctrl + Shift + I
  • F12

2. Перейти на вкладку Network

3. Найти упавший запрос

4. Подробности запроса (нажать на строку)

В данном случае ошибка - статус 404, на сервере не найден метод для такого запроса

Live-coding

Курсовой проект

  1. Редактирование вопроса с ответами
  2. Создать сущность сессии (+ репозиторий + сервис + рест)
  3. Получение списка для реестра сессий (+ поиск)
  4. Получение списка вопросов для новой сессии
  5. Сохранение новой сессии с валидацией ответов
  6. Сохранять список указанных ответов, для сессии
  7. Тесты (в т.ч. на подсчет баллов по ответам в сессии)

Основное задание:

Курсовой проект

хема начисления баллов)

  • В вопросе может быть один или несколько правильных вариантов ответов. Максимальная сумма очков за один вопрос равна 1.
  • Если выбраны неверные опции, то сумма баллов уменьшается. Минимальное количество очков равно нулю.
  • если вариант верный только один, то 1 очко ставится, если выбран именно он, иначе ставится 0
  • если несколько верных вариантов ответа, допустим m из общего количества вариантов n, то количество баллов за вопрос начисляется так:

max(0, k/m - w/(n-m)), где

k - количество выбранных верных вариантов ответа,

w - количество выбранных неверных вариантов ответа.

Курсовой проект

хема начисления баллов)

Алгоритм начисления:

Курсовой проект (дополнительное задание)

*

  • Постраничная навигация в реестре (вопросы, сессии)
  • Фильтрация по количеству ответов в реестре вопросов

***

  • Использовать только клиент из репозитория, а сервер написать полностью самостоятельно

Вопросы

Спасибо за внимание!

Made with Slides.com