REST API Spring 4.x/3.x (Web MVC) и JSON2 Отправляйте запросы, как сделать это правильно раз и навсегда?

Прежде чем углубляться в детали, я знаю, что было много разговоров и связанных вопросов по Stackru. Все они в некотором роде помогают мне, поэтому я решил, что я собрал свои выводы в единый организованный FAQ, чтобы подвести итоги.

Родственные концепции

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

HTTP POST-запрос:

Запрос на публикацию используется, когда вы хотите отправить объект в веб-службу или на серверное приложение.

Сериализация:

Это процесс передачи объекта из вашего веб-браузера в серверное приложение. Можно использовать вызов jQuery Ajax или запрос отправки Curl.

Протоколы сериализации:

Наиболее популярными в эти дни являются JSON и XML. XML становится менее популярным, поскольку сериализованные XML-объекты имеют относительно большие размеры из-за природы тегов XML. В этом FAQ основное внимание уделяется сериализации JSON2.

Весна:

Spring Framework и его мощные аннотации позволяют эффективно использовать веб-сервис. В Spring много разных библиотек. В центре нашего внимания находится Spring Web MVC.

Керл против JQuery:

Это инструменты, которые вы можете использовать для отправки запроса на стороне клиента. Даже если вы планируете использовать JQuery AJAX-вызов, я предлагаю вам использовать Curl для целей отладки, поскольку он предоставляет вам подробный ответ после выполнения запроса на публикацию.

@RequestBody vs @ RequestParam / @ PathVariable vs @ModelAttribute:

В тех случаях, когда у вас есть веб-сервис, который не зависит от вашей модели Java EE, необходимо использовать @RequestBody. Если вы используете модель и ваш объект JSON добавлен в модель, вы можете получить доступ к объекту через @ModelAttribute. Только в тех случаях, когда ваш запрос является либо запросом GET, либо комбинацией запросов GET и POST, вам нужно использовать @ RequestParam / @ PathVariable.

@RequestBody vs @ResposeBody:

Как видно из названия, это так просто: @ResponseBody нужен только в том случае, если вы отправляете ответ клиенту после того, как метод на стороне сервера обработал запрос.

RequestMappingHandlerAdapter vs AnnotationMethodHandlerAdapter:

RequestMappingHandlerAdapter - это новый обработчик отображения для среды Spring, который заменил AnnotationMethodHandlerAdapter начиная с Spring 3.1. Если ваша существующая конфигурация все еще находится в AnnotationMethodHandlerAdapter, этот пост может оказаться полезным. Конфигурация, представленная в моем посте, даст вам представление о том, как настроить RequestMappingHandlerAdapter.

Настроить

Вам нужно будет настроить конвертер сообщений. Вот как ваше сериализованное тело сообщения JSON преобразуется в локальный объект Java на стороне вашего сервера.

Базовая конфигурация отсюда. Конвертерами были MarshallingHttpMessageConverter и CastorMarshaller в базовом примере конфигурации, я заменил их на MappingJackson2HttpMessageConverter и MappingJacksonHttpMessageConverter.

Где поставить конфигурацию

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

  • XML контекста приложения. Один из них - XML-файл контекста приложения, в котором находятся ваш компонент sessionFactory, компонент dataSource и т. Д.
  • Сервлет-диспетчер MVC XML: здесь у вас есть bean-компонент распознавателя вида и вы импортируете XML контекста приложения.

bean-компонент hadlerAdapter должен быть расположен позднее, это XML-файл MVC Dispatcher.

<bean name="handlerAdapter"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    <property name="messageConverters">
        <list>
            <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
            <ref bean="jsonConverter"/>

        </list>

    </property>
    <property name="requireSession" value="false"/>

</bean>
<bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
    <property name="supportedMediaTypes" value="application/json"/>
</bean>

Вы можете иметь несколько конвертеров сообщений. здесь я создал обычный JSON, а также JSON 2 конвертер сообщений. В XML-файле использовался как Ref, так и обычный bean-формат (лично я предпочитаю тег ref в качестве более аккуратного).

REST API

Вот пример контроллера, который предоставляет REST API.

Контроллер

Вот где раскрывается ваш REST API для HTTP-запроса.

@Component
@Controller
@RequestMapping("/api/user")
public class UserController {
@RequestMapping(value = "/add", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public String insertUser(@RequestBody final User user) {
    System.out.println(user.toString());
    userService.insertUser(user);
    String userAdded = "User-> {" + user.toString() + "} is added";
    System.out.println(userAdded);
        return userAdded;
    }
}

Объект Java

@JsonAutoDetect
public class User {

private int id;
private String username;
private String name;
private String lastName;
private String email;

public int getId() {
    return externalId;
}

public void setId(final int id) {
    this.id = id;
}

public String getName() {
    return name;
}

public void setName(final String name) {
    this.name = name;
}

public String getEmail() {
    return email;
}

public void setEmail(final String email) {
    this.email = email;
}
public String getUsername() {
    return username;
}

public void setUsername(final String username) {
    this.username = username;
}

public String getLastName() {
    return lastName;
}

public void setLastName(final String lastName) {
    this.lastName = lastName;
}

@Override
public String toString() {
    return this.getName() + " | " + this.getLastName()  + " | " + this.getEmail()
            + " | " + this.getUsername()  + " | " + this.getId()  + " | ";
    }

}

CURL Почтовый звонок

curl -i -H "Content-Type: application/json" -X POST -d '{"id":100,"username":"JohnBlog","name":"John","lastName":"Blog","email":"JohnBlog@user.com"}' http://localhost:8080/[YOURWEBAPP]/api/user/add

Похожие посты и вопросы

Этот FAQ был бы невозможен, если бы не все люди, которые предоставили следующие посты и вопросы (этот список расширится, если я найду полезные связанные посты / вопросы):

  1. Каков правильный тип содержимого JSON?
  2. Spring 3.0 делает JSON-ответ с использованием конвертера сообщений Джексона
  3. Как отправить данные JSON с помощью Curl из терминала / командной строки для тестирования Spring REST?
  4. Отправка JSON в REST API
  5. https://github.com/geowarin/spring-mvc-examples
  6. Как опубликовать JSON в PHP с помощью curl
  7. Весенний ОТДЫХ | MappingJacksonHttpMessageConverter создает недопустимый JSON
  8. https://github.com/eugenp/REST
  9. Spring Web MVC - проверка отдельных параметров запроса
  10. Как отправить данные JSON с помощью Curl из терминала / командной строки для тестирования Spring REST?
  11. Как вы возвращаете объект JSON из сервлета Java
  12. Какой тип MIME, если JSON возвращается REST API?

2 ответа

Решение

CURL Почтовый звонок

curl -i -H "Content-Type: application/json" -X POST -d '{"id":100,"username":"JohnBlog","name":"John","lastName":"Blog","email":"JohnBlog@user.com"}' http://localhost:8080/[YOURWEBAPP]/api/user/add

Различные сценарии ошибок:

Здесь я исследую различные ошибки, с которыми вы можете столкнуться после того, как вы сделали вызов curl, и что могло произойти не так.

Сценарий первый:

HTTP/1.1 404 Not Found
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=utf-8
Content-Length: 949
Date: Tue, 04 Jun 2013 02:59:35 GMT

Это означает, что REST API не существует в предоставленном вами URL.

Первопричина:
  • У вас может быть опечатка в вашем запросе (поверьте мне, это может произойти)!
  • Возможно, ваша весенняя конфигурация не верна. Если дело обстоит именно так, нужно еще глубже разобраться в том, что на самом деле пошло не так, но я предоставил некоторые начальные действия, которые вам нужно сделать, прежде чем начинать более сложное расследование.
Действия:

После того, как вы убедились, что все сделано совершенно правильно, и нет ничего плохого в вашей конфигурации, ни в вашем URL: - Запустите maven clean. - Разверните ваше веб-приложение или просто удалите его. - Повторно разверните веб-приложение. - Убедитесь, что в вашем maven / gradle используется только одна версия Spring.

Сценарий второй:

HTTP/1.1 400 Bad Request
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=utf-8
Content-Length: 968
Date: Tue, 04 Jun 2013 03:08:05 GMT
Connection: close

Единственная причина этого заключается в том, что ваш запрос отформатирован неправильно. Если вы извлечете подробный ответ curl, вы должны увидеть "Запрос, отправленный клиентом, был синтаксически неверным".

Первопричина:

Либо у вас неправильный формат JSON, либо у вас отсутствует обязательный параметр для объекта JAVA.

Действия:

Убедитесь, что вы предоставили объект JSON в правильном формате и с правильным количеством параметров. Обнуляемые свойства не являются обязательными, но вы должны предоставить данные для всех свойств NotNullable. ОЧЕНЬ важно помнить, что Spring использует отражение Java, чтобы превратить ваш файл JSON в объекты Java, что это значит? это означает, что имена переменных и методов являются CasE SensItiVe. Если ваш JSON-файл отправляет переменную "userName", соответствующая переменная в вашем Java-объекте ДОЛЖНА также иметь имя "userName". Если у вас есть геттеры и сеттеры, они также должны следовать одному и тому же правилу. getUserName и setUserName соответствуют нашему предыдущему примеру.

Senario Three:

HTTP/1.1 415 Unsupported Media Type
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=utf-8
Content-Length: 1051
Date: Wed, 24 Aug 2011 08:50:17 GMT
Первопричина:

Тип мультимедиа Json не поддерживается вашим веб-сервисом. Это может быть связано с тем, что в вашей аннотации не указан тип носителя или вы не указали тип носителя в команде Curl post.

Действия:

Проверьте, правильно ли настроен конвертер сообщений, и убедитесь, что аннотация веб-службы соответствует приведенному выше примеру. Если все в порядке, убедитесь, что вы указали тип содержимого в своем запросе на публикацию Curl.

Тип мультимедиа json не поддерживается вашим веб-сервисом.

Senario N (!):

HTTP/1.1 200 OK 
Server: Apache-Coyote/1.1 
Content-Type: application/json;charset=UTF-8 
Transfer-Encoding: chunked 
Date: Tue, 04 Jun 2013 03:06:16 GMT 

Поздравляю, пользователь фактически отправляет на ваш сервер REST API.

Для получения более подробной информации о том, как настроить пружину, обратитесь к руководству MVC Spring.

Похожие посты и вопросы

Этот FAQ был бы невозможен, если бы не все люди, которые предоставили следующие посты и вопросы (этот список расширится, если я найду полезные связанные посты / вопросы):

  1. Каков правильный тип содержимого JSON?
  2. Spring 3.0 делает JSON-ответ с использованием конвертера сообщений Джексона
  3. Как отправить данные JSON с помощью Curl из терминала / командной строки для тестирования Spring REST?
  4. Отправка JSON в REST API
  5. https://github.com/geowarin/spring-mvc-examples
  6. Как опубликовать JSON в PHP с помощью curl
  7. Весенний ОТДЫХ | MappingJacksonHttpMessageConverter создает недопустимый JSON
  8. https://github.com/eugenp/REST
  9. Spring Web MVC - проверка отдельных параметров запроса
  10. Как отправить данные JSON с помощью Curl из терминала / командной строки для тестирования Spring REST?
  11. Как вы возвращаете объект JSON из сервлета Java
  12. Какой тип MIME, если JSON возвращается REST API?

Должно быть замечено, что класс bean нельзя обрабатывать, если он имеет 2 или более сеттера для одного поля без @JsonIgnore на дополнительные. Весна / Джексон бросить HttpMediaTypeNotSupportedException и http status 415 Unsupported Media Type.

Пример:

@JsonGetter
public String getStatus() {
    return this.status;
}

@JsonSetter
public void setStatus(String status) {
    this.status = status;
}

@JsonIgnore
public void setStatus(StatusEnum status) {
    if (status == null) {
        throw new NullPointerException();
    }

    this.status = status.toString();
}

Обновление: мы также должны указать @JsonGetter а также @JsonSetter в этом случае не должно быть проблем при использовании в качестве возвращаемого типа.

Только что протестировал его с Spring 3.2.2 и Jackson 2.2. Работает нормально как параметр (@RequestBody) и / или в качестве типа возврата (@ResponseBody).

Обновление 2:

Если @JsonGetter а также @JsonSetter указаны, @JsonIgnore кажется, не требуется.

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