-
Notifications
You must be signed in to change notification settings - Fork 3
Lesson 142 (Servlet API. Знакомство с сервлетами) #1
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
base: for-pr
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| package com.walking.servletpractice.converter; | ||
|
|
||
| import com.walking.servletpractice.model.Calculation; | ||
| import com.walking.servletpractice.model.CalculationData; | ||
| import com.walking.servletpractice.model.dto.CalculationDto; | ||
|
|
||
| import java.util.stream.Collectors; | ||
|
|
||
| /** | ||
| * Преобразует объект бизнес-логики {@code Calculation} в dto-объект {@code CalculationDto}, | ||
| * для отправки пользователю. | ||
| */ | ||
| public class CalculationConverter implements Converter<Calculation, CalculationDto> { | ||
| @Override | ||
| public CalculationDto convert(Calculation calculation) { | ||
| var calculationDto = new CalculationDto(); | ||
|
|
||
| calculationDto.setType(calculation.getType() | ||
| .getValue()); | ||
|
Owner
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. спорный момент. Если клиентом выступает фронтовая апликуха - она уж как-нибудь сама строковый литерал для енама смапит в то, что ей нужно. Если же у тебя сервер раздает фактическое отображение (html или что ты собрался в браузере рисовать) - зачем тебе вообще DTO? Конвертируй сразу доменный объект в страничку:) На самом деле, расклад домен->дто->html тоже имеет право на жизнь, но не в этой же задачке на 4 строки кода. Тут просто не на чем пордемонстрировать разумность такого подхода |
||
|
|
||
| calculationDto.setData(calculation.getData() | ||
| .stream() | ||
|
Owner
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. не пихай цепочки стримов в параметр. Всегда выглядит как колхоз и читается дерьмово |
||
| .map(CalculationData::toString) | ||
|
Owner
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. Строго говоря, toString() не особо предназначен для таких ситуаций. Так можно делать в совсем учебных задачках для начинающих, но здесь уже моветон. toString() ок для каких-нить логов, мб в каких-то редких случаях - как часть exception message. Но точно не в основной логике. Хотя бы потому что в логике может потребоваться несколько различных вариантов отображений в виде строки, в зависимости от контекста использования Нужен строковый эквивалент объекта - выдели отдельный метод или класс, который будет превращать твою модель в строку |
||
| .collect(Collectors.toList())); | ||
|
Owner
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. Тут же джава повыше 11? Тогда зачем изменяемая коллекция? |
||
|
|
||
| calculationDto.setResult(calculation.getResult() | ||
| .toString()); | ||
|
Owner
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. Зачем ты вообще отображаешь объект как строку - тоже открытый вопрос. Того же рода, что и конвертация енама в хрен пойми что:) |
||
|
|
||
| return calculationDto; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| package com.walking.servletpractice.converter; | ||
|
|
||
| import com.walking.servletpractice.model.Calculation; | ||
| import com.walking.servletpractice.model.request.CalculationRequest; | ||
| import com.walking.servletpractice.service.CalculationService; | ||
|
|
||
| /** | ||
| * Преобразует dto-объект {@code CalculationRequest} в объект бизнес-логики {@code Calculation}. | ||
| * Объект {@code Calculation} запрашивается у {@code CalculationService}, который отвечает за вычисления. | ||
| */ | ||
| public class CalculationRequestConverter implements Converter<CalculationRequest, Calculation> { | ||
| private final CalculationService calculationService; | ||
|
|
||
| public CalculationRequestConverter(CalculationService calculationService) { | ||
| this.calculationService = calculationService; | ||
| } | ||
|
|
||
| @Override | ||
| public Calculation convert(CalculationRequest source) { | ||
| return calculationService.calculated(source.getType(), source.getData()); | ||
|
Owner
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. Конвертер должен заниматься конвертацией - подготовкой моделей одного архитектурного слоя для использования в другом. Но не вызывать бинзес-логику
Owner
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. В данном случае я вообще не вижу смысла в конвертере, проще в сервис два аргумента передать прямо в сервлете (или откуда ты этот конвертер вызываешь) |
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| package com.walking.servletpractice.converter; | ||
|
|
||
| public interface Converter<S, R> { | ||
| R convert(S source); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package com.walking.servletpractice.exception; | ||
|
|
||
| public class ParsingException extends RuntimeException { | ||
| public ParsingException() { | ||
|
Owner
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. зачем? |
||
| } | ||
|
|
||
| public ParsingException(String value, Throwable cause) { | ||
| super("Cannot parse value: '%s'".formatted(value), cause); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| package com.walking.servletpractice.model; | ||
|
Owner
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. тут можно потиху заводить мой любимый пакет - domain. Те же модельки, но для доменного слоя. А model оставить для dto и прочего вспомогательного говна |
||
|
|
||
| import java.util.List; | ||
|
|
||
| /** | ||
| * Объект бизнес-логики отражающий конкретное вычисление. Инкапсулирует данные | ||
|
Owner
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. Это что угодно, но не объект Объект бизнес-логики:) Доменная моделька - да |
||
| * о типе вычисления, данных для вычисления и результате вычисления. | ||
| */ | ||
| public class Calculation { | ||
| private final CalculationType type; | ||
| private final List<CalculationData> data; | ||
|
Owner
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. дело хозяйское, но не инициализированный список - это предвестник неожиданного NPE:) |
||
| private final CalculationResult result; | ||
|
|
||
| public Calculation(CalculationType type, List<CalculationData> data, CalculationResult result) { | ||
| this.type = type; | ||
| this.data = data; | ||
| this.result = result; | ||
| } | ||
|
|
||
| public CalculationType getType() { | ||
| return type; | ||
| } | ||
|
|
||
| public List<CalculationData> getData() { | ||
| return data; | ||
| } | ||
|
|
||
| public CalculationResult getResult() { | ||
| return result; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| package com.walking.servletpractice.model; | ||
|
|
||
| /** | ||
| * Объект-значение инкапсулирующий данные, используемые для вычислений. | ||
| */ | ||
| public class CalculationData { | ||
| private final double value; | ||
|
|
||
| public CalculationData(double value) { | ||
| this.value = value; | ||
| } | ||
|
|
||
| public double getValue() { | ||
| return value; | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return Double.toString(value); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| package com.walking.servletpractice.model; | ||
|
|
||
| /** | ||
| * Объект-значение инкапсулирующий значение результата вычисления. | ||
| */ | ||
| public class CalculationResult { | ||
| private final double value; | ||
|
|
||
| public CalculationResult(double value) { | ||
| this.value = value; | ||
| } | ||
|
|
||
| public double getValue() { | ||
| return value; | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return Double.toString(value); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| package com.walking.servletpractice.model; | ||
|
|
||
| import java.util.NoSuchElementException; | ||
|
|
||
| /** | ||
| * Ограничивает список типов арифметических операций, которые могут быть обработаны. | ||
| */ | ||
| public enum CalculationType { | ||
| ADDITION("addition"), | ||
| SUBTRACTION("subtraction"), | ||
| MULTIPLICATION("multiplication"), | ||
| DIVISION("division"); | ||
|
|
||
| private final String value; | ||
|
|
||
| CalculationType(String value) { | ||
| this.value = value; | ||
| } | ||
|
|
||
| public String getValue() { | ||
| return value; | ||
| } | ||
|
|
||
| public static CalculationType getByValue(String value) { | ||
| for (CalculationType type : CalculationType.values()) { | ||
| if (type.getValue() | ||
| .equals(value)) { | ||
|
Owner
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. такие переносы очень плохо читаются. Хочешь переносить - выдели в переменную. Но как по мне здесь и в одну строку норм - NPE негде упасть |
||
| return type; | ||
| } | ||
| } | ||
|
|
||
| throw new NoSuchElementException( | ||
| "Cannot get CalculationType from value: '%s'".formatted(value)); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| package com.walking.servletpractice.model.dto; | ||
|
|
||
| import java.util.List; | ||
| import java.util.StringJoiner; | ||
|
|
||
| /** | ||
| * Dto-объект, содержащий данные вычисления, возвращаемые пользователю. | ||
| */ | ||
| public class CalculationDto { | ||
| private static final String ARGUMENT_DELIMITER = "&"; | ||
| private static final String NAME_VALUE_DELIMITER = "="; | ||
| private static final String VALUES_DELIMITER = ","; | ||
|
|
||
| private String type; | ||
| private List<String> data; | ||
| private String result; | ||
|
|
||
| public void setType(String type) { | ||
| this.type = type; | ||
| } | ||
|
|
||
| public void setData(List<String> data) { | ||
| this.data = data; | ||
| } | ||
|
|
||
| public void setResult(String result) { | ||
| this.result = result; | ||
| } | ||
|
|
||
| /** | ||
| * Преобразует данные вычислений в строку вида: "type=value&data=value1,valueN&result=value" | ||
| */ | ||
| @Override | ||
| public String toString() { | ||
|
Owner
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. все о том же. Не под эту задачу данный метод |
||
| var argumentJoiner = new StringJoiner(ARGUMENT_DELIMITER); | ||
|
|
||
| addType(argumentJoiner); | ||
| addData(argumentJoiner); | ||
| addResult(argumentJoiner); | ||
|
|
||
| return argumentJoiner.toString(); | ||
| } | ||
|
|
||
| private void addType(StringJoiner stringJoiner) { | ||
| stringJoiner.add("type" + NAME_VALUE_DELIMITER + type); | ||
| } | ||
|
|
||
| private void addData(StringJoiner stringJoiner) { | ||
| var valuesJoiner = new StringJoiner(VALUES_DELIMITER); | ||
|
|
||
| for (String value : data) { | ||
| valuesJoiner.add(value); | ||
| } | ||
|
|
||
| stringJoiner.add("data" + NAME_VALUE_DELIMITER + valuesJoiner); | ||
| } | ||
|
|
||
| private void addResult(StringJoiner stringJoiner) { | ||
| stringJoiner.add("result" + NAME_VALUE_DELIMITER + result); | ||
| } | ||
|
Owner
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. Я бы какой-нить отдельный класс-сериализатор выделил. Императивная сериализация внутри модели почти всегда стреляет в ногу |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| package com.walking.servletpractice.model.request; | ||
|
|
||
| import com.walking.servletpractice.model.CalculationData; | ||
| import com.walking.servletpractice.model.CalculationType; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| /** | ||
| * Dto-объект, содержащий данные для вычислений, полученные от пользователя. | ||
| */ | ||
| public class CalculationRequest { | ||
| private CalculationType type; | ||
| private List<CalculationData> data; | ||
|
|
||
| public CalculationType getType() { | ||
| return type; | ||
| } | ||
|
|
||
| public void setType(CalculationType type) { | ||
| this.type = type; | ||
| } | ||
|
|
||
| public List<CalculationData> getData() { | ||
| return data; | ||
| } | ||
|
|
||
| public void setData(List<CalculationData> data) { | ||
| this.data = data; | ||
| } | ||
| } |
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.
избыточная документация - она как лишние гандоны. Надежно, но портит ощущения