Чистый код для частичного исправления доменного класса в Spring @PatchMapping?

Весной я пишу такой код для обработки запроса PATCH:

@PatchMapping(path = "/{orderId}", consumes = "application/json")
public Order patchOrder(@PathVariable("orderId") Long orderId, @RequestBody Order patch) {
    Order order = repo.findById(orderId).get();
    if (patch.getDeliveryName() != null) {
        order.setDeliveryName(patch.getDeliveryName());
    }
    if (patch.getDeliveryStreet() != null) {
        order.setDeliveryStreet(patch.getDeliveryStreet());
    }
    if (patch.getDeliveryCity() != null) {
        order.setDeliveryCity(patch.getDeliveryCity());
    }
    //...
    //Check all fields in Order class.
    return repo.save(order);
}

Очевидно, здесь есть как минимум два недостатка:

  1. Код не чистый из-за большого количества проверок на null.
  2. Даже если абстрагировать нулевую проверку в функции, все равно остаются проблемы, когда мы меняем определение класса Order. То есть при удалении полей или добавлении новых полей в класс Order этот фрагмент кода также необходимо переписать.

Я знаю, что могу выполнить некоторую проверку на null на стороне клиента, например, отправлять только ненулевые поля для выполнения PATCH, но мне интересно, есть ли элегантный способ сделать это? Как сопоставление объектов или другие способы?

Лично я не думаю, что это нечисто - это просто повторение. Если вам случится изменить определение Order, я бы подумал, что лучше, чтобы эта часть приложения была сломана (во время компиляции). Фактически, если бы я изменил класс предметной области и ничего не сломалось, я бы, вероятно, почувствовал себя параноиком.

Jai 10.12.2018 08:10

@Jai Вау, думаю, я понял. Похоже, я перепутал «не чистое» и «повторяющееся».

callofdutyops 10.12.2018 08:27

@Patrick Я провожу проверку в некоторых случаях, например, в классе домена формы. Но в этой ситуации пустое поле в запросе PATCH не означает недопустимое, это может означать, что это поле остается нетронутым.

callofdutyops 10.12.2018 08:36

Я тоже не считаю, что это неправильно. Но я бы хотел изменить одну вещь: Order order = repo.findById(orderId).get(); на что-то более подходящее, например orElseThrow(), и я также не большой поклонник логики внутри классов контроллеров. Я бы предпочел вызвать сервисный метод и провести там проверку.

Pijotrek 10.12.2018 08:42
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
3
4
260
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы можете определить новый тип параметра, например OrderPatch, с дополнительными полями. (Spring выполняет сопоставление с Optional за вас). В теле метода patchOrder () вы можете использовать Optional.orElse () со значением существующего порядка по умолчанию, без операторов if.

Ответ принят как подходящий

Первым делом вместо проверки просто null, как показано ниже:

if (patch.getDeliveryName() != null) {
    order.setDeliveryName(patch.getDeliveryName());
}

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

order.setDeliveryName(StringUtils.isEmpty(patch.getDeliveryName()) ? "" : patch.getDeliveryName());

Также с помощью метода Spring проверяется наличие нулевых и пустых значений.

А для точки "б" вы можете использовать приведенный ниже код:

BeanUtils.copyProperties(bean2, bean1);

добавить следующую зависимость в pom.xml

<dependency>
    <groupId>commons-beanutils</groupId>
    <artifactId>commons-beanutils</artifactId>
    <version>1.9.3</version>
</dependency>

Перенесите nullchecker в сеттер:

  Order order = repo.findById(orderId).get();
  order.setByPatch(patch)

внутри класса Order

  public void setByPatch(Patch patch){
    this.setDeliveryName(patch.getDeliveryName());
    this.setDeliveryStreet(patch.getDeliveryStreet());
    this.setDeliveryCity(patch.getDeliveryCity());
  }

затем добавьте к сеттерам NullCheck ...

=========================================== Или вы можете обратиться к: https://docs.spring.io/spring/docs/4.1.x/spring-framework-reference/html/validation.html

И добавьте @Valid к Order в порядке @RequestBody @Validated Order. А затем установите @NotNull, @NotBlank

Другие вопросы по теме