Nano Hash - криптовалюты, майнинг, программирование

Расшифровка параметров тела с помощью Spring

Я разрабатываю серверную часть REST API с помощью Spring для приложения Slack. Мне удалось получать сообщения от Slack (команды с косой чертой), но я не могу правильно получать взаимодействия компонентов (нажатия кнопок).

В официальной документации говорится:

Ваш URL-адрес действия получит HTTP-запрос POST, включая параметр тела полезной нагрузки, который сам содержит строку JSON application / x-www-form-urlencoded.

поэтому я написал следующее @RestController:

@RequestMapping(method = RequestMethod.POST, value = "/actions", headers = {"content-type=application/x-www-form-urlencoded"})
public ResponseEntity action(@RequestParam("payload") ActionController.Action action) {
    return ResponseEntity.status(HttpStatus.OK).build();
}

@JsonIgnoreProperties(ignoreUnknown = true)
class Action {

    @JsonProperty("type")
    private String type;

    public Action() {}

    public String getType() {
        return type;
    }

}

однако я получаю следующую ошибку:

Failed to convert request element: org.springframework.web.method.annotation.MethodArgumentConversionNotSupportedException: Failed to convert value of type 'java.lang.String' to required type 'controllers.ActionController$Action'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'controllers.ActionController$Action': no matching editors or conversion strategy found

Что это значит и как решить?


  • две вещи. 1. Сделайте Action отдельным классом вместо внутреннего класса. У Джексона есть проблема с десериализацией во внутренние классы. 2 какое тело отправляется на эту конечную точку. 30.08.2018
  • На эту конечную точку отправляется тело payload=%7B%22type%22%3A%22interactive_message%22%2C%22trigger_id%22%3A%22425937372067.385758389520.d1fe461bd1de87428efb097e09babee7%22%7D 30.08.2018
  • строка выше является частью URL-адреса? или это часть тела сообщения POST? Если это часть URL-адреса, тогда решение должно действовать так, как предложил @davidxxx. Если это часть полезной нагрузки Post Message, тогда используйте @RequestBody вместо @RequestParam, и spring автоматически преобразует это в ваш класс Action 30.08.2018
  • @pvpkiran Это интересная идея. На самом деле {...} не JSON отправляется непосредственно в тело запроса, а значение параметра полезной нагрузки, добавляемого в тело запроса. Как вы думаете, Spring сможет все-таки выполнить преобразование в пользовательский класс? 30.08.2018
  • @davidxxx Нет, Spring не может этого сделать, если это не json. потому что весна полагается на Джексона, чтобы преобразовать 30.08.2018

Ответы:


1

Вы получаете строку, содержащую содержимое JSON. Вы не получаете ввод JSON, поскольку application/x-www-form-urlencoded используется как тип содержимого, а не application/json, как указано:

Ваш URL-адрес действия получит HTTP-запрос POST, включая параметр тела полезной нагрузки, который сам содержит строку JSON application / x-www-form-urlencoded.

Поэтому измените тип параметра на String и используйте Джексон или любую библиотеку JSON для сопоставления String с вашим классом Action:

@RequestMapping(method = RequestMethod.POST, value = "/actions", headers = {"content-type=application/x-www-form-urlencoded"})
public ResponseEntity action(@RequestParam("payload") String actionJSON) {
    Action action = objectMapper.readValue(actionJSON, Action.class);  
    return ResponseEntity.status(HttpStatus.OK).build();
}

Как предлагает pvpkiran, вы могли бы заменить @RequestParam на @RequestBody, если бы вы могли передавать строку JSON непосредственно в теле запроса POST, а не как значение параметра, но, похоже, это не так.
Действительно, by при использовании @RequestBody тело запроса передается через HttpMessageConverter для разрешения аргумента метода.

Чтобы ответить на ваш комментарий, Spring MVC не предоставляет очень простой способ выполнить ваше требование: сопоставить String JSON с вашим классом Action.
Но если вам действительно нужно автоматизировать это преобразование, у вас есть длинная альтернатива, как указано в Spring Документация по MVC, например форматировщики (выделено мной):

Некоторые аннотированные аргументы метода контроллера, которые представляют ввод строкового запроса - например, @RequestParam, @RequestHeader, @PathVariable, @MatrixVariable, и @CookieValue могут потребовать преобразования типа, если аргумент объявлен как нечто иное, чем String.

Для таких случаев автоматически применяется преобразование типов в зависимости от настроенных преобразователей. По умолчанию поддерживаются простые типы, такие как int, long, Date и т. Д. Преобразование типов можно настроить с помощью WebDataBinder, см. DataBinder, или путем регистрации средств форматирования с помощью FormattingConversionService, см. раздел Форматирование полей Spring.

Создав модуль форматирования (подкласс FormatterRegistry) для вашего класса Action, вы можете добавить его в веб-конфигурацию Spring в соответствии с документацией:

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addFormatters(FormatterRegistry registry) {
        // ... add action formatter here
    }
}

и используйте его в объявлении параметра:

public ResponseEntity action(@RequestParam("payload") @Action Action actionJ) 
{...}
30.08.2018
  • Это действительно работает, но мне кажется, что это обходной путь, а не решение. Неужели у Spring / Jackson действительно нет способа сделать то же самое автоматически? 30.08.2018
  • @Andrea К сожалению, нет. Автоматические функции зависят от того, соблюдает ли другая сторона стандартные способы выполнения действий, такие как отказ от двойного кодирования полезной нагрузки без разумной причины. 30.08.2018
  • Редактировал с глупой штукой. Понятия не имею, правда. Может быть, Хрилис права. 30.08.2018
  • @Andrea Непростое решение, но вы можете автоматизировать преобразование JSON - ›Действия. 30.08.2018

  • 2

    Для простоты вы можете использовать приведенный ниже блок кода. Тело @Request сопоставляет полезные данные с классом Action. Он также проверяет, не является ли тип пустым. @Valid и @NotBlank из пакета javax.validation.

        @PostMapping("actions")
    public ResponseEntity<?> startApplication(@RequestBody @Valid Action payload) {
        // use your payload here 
        return ResponseEntity.ok('done');
    }
    
    
    class Action {
    
        @NotBlank
        private String type;
    
        public Action() {
        }
    
        public String getType() {
            return type;
        }
    }
    
    30.08.2018
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

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

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..