Repository navigation
Выполнить задание 9 спринта: добавить работу с http сервером #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package ru.yandex.javacourse.exceptions; | ||
|
|
||
| public class NotFoundException extends RuntimeException { | ||
| public NotFoundException(String message) { | ||
| super(message); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| package ru.yandex.javacourse.http; | ||
|
|
||
| public enum HttpStatusCode { | ||
| OK(200), | ||
| CREATED(201), | ||
| NOT_FOUND(404), | ||
| NOT_ACCEPTABLE(406), | ||
| INTERNAL_SERVER_ERROR(500); | ||
|
|
||
| final int code; | ||
|
|
||
| HttpStatusCode(int code) { | ||
| this.code = code; | ||
| } | ||
|
|
||
| public int getCode() { | ||
| return code; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| package ru.yandex.javacourse.http; | ||
|
|
||
| import com.google.gson.Gson; | ||
| import com.google.gson.GsonBuilder; | ||
| import com.sun.net.httpserver.HttpServer; | ||
| import ru.yandex.javacourse.http.adapter.DurationTypeAdapter; | ||
| import ru.yandex.javacourse.http.adapter.LocalDateTimeTypeAdapter; | ||
| import ru.yandex.javacourse.http.handler.*; | ||
| import ru.yandex.javacourse.model.Epic; | ||
| import ru.yandex.javacourse.model.Subtask; | ||
| import ru.yandex.javacourse.model.Task; | ||
| import ru.yandex.javacourse.service.Managers; | ||
| import ru.yandex.javacourse.service.TaskManager; | ||
|
|
||
| import java.io.IOException; | ||
| import java.net.InetSocketAddress; | ||
| import java.time.Duration; | ||
| import java.time.LocalDateTime; | ||
|
|
||
| public class HttpTaskServer { | ||
| private final int port; | ||
| private final TaskManager taskManager; | ||
| private HttpServer httpServer; | ||
| private static Gson gson = new GsonBuilder() | ||
| .setPrettyPrinting() | ||
| .serializeNulls() | ||
| .registerTypeAdapter(LocalDateTime.class, new LocalDateTimeTypeAdapter()) | ||
| .registerTypeAdapter(Duration.class, new DurationTypeAdapter()) | ||
| .create(); | ||
|
|
||
| public HttpTaskServer() { | ||
| taskManager = Managers.getDefault(); | ||
| port = 8080; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. порт даже можно было вынести в константу, но твое решение корректно также |
||
| gson = new GsonBuilder() | ||
| .setPrettyPrinting() | ||
| .serializeNulls() | ||
| .registerTypeAdapter(LocalDateTime.class, new LocalDateTimeTypeAdapter()) | ||
| .registerTypeAdapter(Duration.class, new DurationTypeAdapter()) | ||
| .create(); | ||
| } | ||
|
|
||
| public HttpTaskServer(TaskManager taskManager) { | ||
| this.taskManager = taskManager; | ||
| port = 8080; | ||
| } | ||
|
|
||
| public HttpTaskServer(TaskManager taskManager, int port) { | ||
| this.taskManager = taskManager; | ||
| this.port = port; | ||
| } | ||
|
|
||
| public static Gson getGson() { | ||
| return gson; | ||
| } | ||
|
|
||
| public static void main(String[] args) throws IOException { | ||
| HttpTaskServer httpTaskServer = new HttpTaskServer(); | ||
| httpTaskServer.start(); | ||
| httpTaskServer.taskManager.addTask(new Task("Звонок бабушке", | ||
| "Позвонить, чтобы узнать новости")); | ||
| httpTaskServer.taskManager.addTask(new Task("Стирка", | ||
| "Постирать белые вещи")); | ||
|
|
||
| Epic epic1 = httpTaskServer.taskManager.addEpic(new Epic("Сделать домашнее задание", | ||
| "Задание для 6 спринта")); | ||
| httpTaskServer.taskManager.addSubtask(new Subtask("Изучить теорию", | ||
| "Прочитать теорию на сайте", epic1.getId())); | ||
| httpTaskServer.taskManager.addSubtask(new Subtask("Освоить тренажёр", | ||
| "Выполнить все задания", epic1.getId())); | ||
| httpTaskServer.taskManager.addSubtask(new Subtask("Прослушать вебинар", | ||
| "Подключиться на вебинар в среду", epic1.getId())); | ||
|
|
||
| //httpTaskServer.stop(); | ||
|
|
||
| } | ||
|
|
||
| public void start() throws IOException { | ||
| httpServer = HttpServer.create(new InetSocketAddress(port), 0); | ||
| httpServer.createContext("/tasks", new TaskHandler(taskManager, gson)); | ||
| httpServer.createContext("/subtasks", new SubtaskHandler(taskManager, gson)); | ||
| httpServer.createContext("/epics", new EpicHandler(taskManager, gson)); | ||
| httpServer.createContext("/history", new HistoryHandler(taskManager, gson)); | ||
| httpServer.createContext("/prioritized", new PrioritizedHandler(taskManager, gson)); | ||
| httpServer.start(); | ||
| System.out.println("HTTP-сервер запущен на " + port + " порту!"); | ||
| } | ||
|
|
||
| public void stop() { | ||
| httpServer.stop(1); | ||
| System.out.println("HTTP-сервер остановлен на " + port + " порту!"); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| package ru.yandex.javacourse.http.adapter; | ||
|
|
||
| import com.google.gson.TypeAdapter; | ||
| import com.google.gson.stream.JsonReader; | ||
| import com.google.gson.stream.JsonWriter; | ||
|
|
||
| import java.io.IOException; | ||
| import java.time.Duration; | ||
|
|
||
| public class DurationTypeAdapter extends TypeAdapter<Duration> { | ||
| @Override | ||
| public void write(JsonWriter jsonWriter, Duration duration) throws IOException { | ||
| if (duration == null) { | ||
| jsonWriter.nullValue(); | ||
| } else { | ||
| jsonWriter.value(String.valueOf(duration.toMinutes())); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public Duration read(JsonReader jsonReader) throws IOException { | ||
| try { | ||
| String value = jsonReader.nextString(); | ||
| if (value == null || value.equals("null")) { | ||
| return null; | ||
| } | ||
| return Duration.ofMinutes(Long.parseLong(value)); | ||
| } catch (Exception e) { | ||
| jsonReader.nextNull(); | ||
| return null; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. да корректно. но увлекаться возвратами null нужно очень аккуратно так как это может привести к скрытым багам npe |
||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| package ru.yandex.javacourse.http.adapter; | ||
|
|
||
| import com.google.gson.TypeAdapter; | ||
| import com.google.gson.stream.JsonReader; | ||
| import com.google.gson.stream.JsonWriter; | ||
|
|
||
| import java.io.IOException; | ||
| import java.time.LocalDateTime; | ||
| import java.time.format.DateTimeFormatter; | ||
|
|
||
| public class LocalDateTimeTypeAdapter extends TypeAdapter<LocalDateTime> { | ||
| private final DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss"); | ||
|
|
||
| @Override | ||
| public void write(JsonWriter jsonWriter, LocalDateTime localDateTime) throws IOException { | ||
| if (localDateTime == null) { | ||
| jsonWriter.nullValue(); | ||
| } else { | ||
| jsonWriter.value(localDateTime.format(timeFormatter)); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public LocalDateTime read(JsonReader jsonReader) throws IOException { | ||
| try { | ||
| String value = jsonReader.nextString(); | ||
| if (value == null || value.equals("null")) { | ||
| return null; | ||
| } | ||
| return LocalDateTime.parse(value, timeFormatter); | ||
| } catch (Exception exception) { | ||
| jsonReader.nextNull(); | ||
| return null; | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| package ru.yandex.javacourse.http.handler; | ||
|
|
||
| import com.google.gson.Gson; | ||
| import com.google.gson.JsonElement; | ||
| import com.google.gson.JsonObject; | ||
| import com.google.gson.JsonParser; | ||
| import com.sun.net.httpserver.HttpExchange; | ||
| import com.sun.net.httpserver.HttpHandler; | ||
| import ru.yandex.javacourse.http.HttpStatusCode; | ||
| import ru.yandex.javacourse.service.TaskManager; | ||
|
|
||
| import java.io.IOException; | ||
| import java.io.OutputStream; | ||
| import java.nio.charset.Charset; | ||
| import java.nio.charset.StandardCharsets; | ||
| import java.util.Optional; | ||
|
|
||
| abstract class BaseHttpHandler implements HttpHandler { | ||
| private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; | ||
| protected TaskManager taskManager; | ||
| protected Gson gson; | ||
|
|
||
| protected BaseHttpHandler(TaskManager taskManager, Gson gson) { | ||
| this.taskManager = taskManager; | ||
| this.gson = gson; | ||
| } | ||
|
|
||
| /** | ||
| * Основной метод, который обрабатывает входящий запрос | ||
| */ | ||
| @Override | ||
| public abstract void handle(HttpExchange exchange) throws IOException; | ||
|
|
||
| /** | ||
| * Отправляет ответ от сервера клиенту с указанным кодом. | ||
| * Используется для отправки 200 и 201 ответов | ||
| */ | ||
| protected void sendText(HttpExchange exchange, String response, int responseCode) { | ||
| try (OutputStream outputStream = exchange.getResponseBody()) { | ||
| exchange.getResponseHeaders().add("Content-Type", "application/json;charset=utf-8"); | ||
| exchange.sendResponseHeaders(responseCode, 0); | ||
| outputStream.write(response.getBytes(DEFAULT_CHARSET)); | ||
| } catch (IOException exception) { | ||
| System.out.println("Возникла проблема при отправке ответа выполнения метода"); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Отправляет ответ от сервера клиенту с кодом 404. | ||
| * Используется для отправки сообщения о том, что элемент не найден | ||
| */ | ||
| protected void sendNotFound(HttpExchange exchange, String response) { | ||
| try (OutputStream outputStream = exchange.getResponseBody()) { | ||
| exchange.getResponseHeaders().add("Content-Type", "application/json;charset=utf-8"); | ||
| exchange.sendResponseHeaders(HttpStatusCode.NOT_FOUND.getCode(), 0); | ||
| outputStream.write(response.getBytes(DEFAULT_CHARSET)); | ||
| } catch (IOException exception) { | ||
| System.out.println("Возникла проблема при отправке ответа о том, что элемент не найден"); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Отправляет ответ от сервера клиенту с кодом 406. | ||
| * Используется для отправки сообщения о том, что элемент пересекается с уже существующими | ||
| */ | ||
| protected void sendHasInteractions(HttpExchange exchange, String response) { | ||
| try (OutputStream outputStream = exchange.getResponseBody()) { | ||
| exchange.getResponseHeaders().add("Content-Type", "application/json;charset=utf-8"); | ||
| exchange.sendResponseHeaders(HttpStatusCode.NOT_ACCEPTABLE.getCode(), 0); | ||
| outputStream.write(response.getBytes(DEFAULT_CHARSET)); | ||
| } catch (IOException exception) { | ||
| System.out.println("Возникла проблема при отправке ответа о том, что объект пересекается с существующим"); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Возвращает Id задачи из запроса | ||
| */ | ||
| public Optional<Integer> getIdFromRequestBody(String requestBody) { | ||
| JsonElement jsonElement = JsonParser.parseString(requestBody); | ||
|
|
||
| if (!jsonElement.isJsonObject()) { | ||
| System.out.println("Невозможно получить номер задачи. Проверьте корректность запроса"); | ||
| return Optional.empty(); | ||
| } | ||
|
|
||
| JsonObject jsonObject = jsonElement.getAsJsonObject(); | ||
| JsonElement idElement = jsonObject.get("id"); | ||
|
|
||
| if (idElement == null || idElement.getAsInt() == 0) { | ||
| return Optional.empty(); | ||
| } | ||
|
|
||
| return Optional.of(idElement.getAsInt()); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
хорошее решение вынести статус коды в енам. лайк!