Spring 4.x/3.x(Web MVC) REST API и JSON2 Почтовые запросы, как правильно это сделать один раз для всех?
Прежде чем вдаваться в подробности, я знаю, что в Stackoverflow было много разговоров и связанных вопросов. Все они мне помогают по-разному, поэтому я думал, что все свои выводы я собрал в виде единого организованного FAQ, чтобы обобщить мои выводы.
Понятия, связанные с данным
Конечно, вы знаете об этом, но я просто пишу их как быстрый обзор. Не стесняйтесь редактировать, если я что-то не хватает.
Запрос HTTP POST:
Пост-запрос используется, когда вы хотите отправить объект в веб-службу или на серверное приложение.
Сериализация:
Является процессом получения объекта из вашего веб-браузера до вашего приложения на стороне сервера. Можно использовать вызов jQuery Ajax или запрос на публикацию Curl.
Протоколы сериализации:
Наиболее популярными тезисами являются JSON и XML. XML становится менее популярным, поскольку сериализованные объекты xml относительно большие по размеру из-за характера тегов XML. В этом FAQ основное внимание уделяется сериализации JSON2.
Spring:
Spring и его мощная аннотация позволяет эффективно публиковать веб-службу. В Spring существует множество разных библиотек. Здесь мы сосредоточены на Spring веб-MVC.
Curl vs 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 bean, dataSource bean и т.д.
- MVC Dispatcher Servlet XML:
Здесь вы обнаружите свой преобразователь вида bean и импортируете XML-контекст приложения.
haslerAdapter bean должен быть расположен в более поздней версии, это файл MVC Dispatcher XML.
<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. Оба формата Ref и normal bean в файле XML были использованы (лично я предпочитаю тег ref как его опрятный).
API REST
Вот пример контроллера, который предоставляет API REST.
Контроллер
Здесь отображается ваш 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":"[email protected]"}' http://localhost:8080/[YOURWEBAPP]/api/user/add
Связанные сообщения и вопросы
Этот FAQ не был возможен, если бы это было не для всех людей, которые предоставили следующие должности и вопросы (этот список будет расширяться, если я столкнусь с полезными сообщениями/вопросами):
Ответы
Ответ 1
CURL Почтовый вызов
curl -i -H "Content-Type: application/json" -X POST -d '{"id":100,"username":"JohnBlog","name":"John","lastName":"Blog","email":"[email protected]"}' http://localhost:8080/[YOURWEBAPP]/api/user/add
Различные сценарии ошибок:
Здесь я исследую различные ошибки, которые могут возникнуть после того, как вы совершили поворот и что, возможно, пошло не так.
Сценарий первый:
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
Это означает, что API REST не существует в указанном вами URL-адресе.
Основная причина:
- У вас может быть опечатка в вашем запросе (поверьте, это может случиться)!
- Возможно, ваша конфигурация spring неверна. Если это так, ему нужно еще больше углубиться в то, что на самом деле пошло не так, но я предусмотрел некоторые начальные действия, которые вам нужно предпринять, прежде чем начинать более сложное исследование.
Действия:
После того, как вы убедитесь, что все сделано совершенно правильно, и ничего не случилось с вашей конфигурацией или вы не указали URL:
- Запустите maven clean.
- Разверните свое веб-приложение или просто удалите его.
- Повторное развертывание веб-приложения
- Обязательно используйте только одну версию spring в своем maven/gradle
Сценарий второй:
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
Единственная причина этого заключается в том, что ваш запрос не отформатирован правильно. Если вы проверите подробный отклик, вы сможете увидеть "Запрос, отправленный клиентом, был синтаксически неправильным".
Основная причина:
Либо ваш формат JSON не прав, либо у вас отсутствует обязательный параметр для объекта JAVA.
Действия:
Убедитесь, что вы предоставили объект JSON в правильном формате и с правильным количеством параметров. Неверные свойства не являются обязательными, но вам необходимо предоставить данные для всех свойств NotNullable. ОЧЕНЬ важно помнить, что spring использует отражение Java, чтобы превратить ваш JSON файл в объекты Java, что это значит? это означает, что имена переменных и методов являются CasE SensItiVe. Если ваш JSON файл отправляет переменную "userName", то ваша соответствующая переменная в вашем Java-объекте ДОЛЖНА также быть названа "userName". Если у вас есть получатели и сеттеры, они также должны следовать тому же правилу. getUserName и setUserName, чтобы соответствовать нашему предыдущему примеру.
Сенарио три:
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 не поддерживается вашей веб-службой. Это может быть связано с вашей аннотацией, не указывающей тип носителя, или вы не указываете тип носителя в команде Post Curl.
Действия:
Проверьте правильность настройки вашего конвертера сообщений и убедитесь, что аннотация веб-службы соответствует приведенному выше примеру. Если все было в порядке, убедитесь, что вы указываете тип контента в запросе на отправку 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 вашей серверной части.
Подробнее о настройке spring руководства spring mvc.
Связанные сообщения и вопросы
Этот FAQ не был возможен, если бы это было не для всех людей, которые предоставили следующие должности и вопросы (этот список будет расширяться, если я столкнусь с полезными сообщениями/вопросами):
Ответ 2
Следует отметить, что класс bean может обрабатывать NOT, если он имеет 2 или более сеттера для одного поля без @JsonIgnore
на дополнительных. Spring/Jackson throw HttpMediaTypeNotSupportedException
и статус http 415 Неподдерживаемый тип носителя.
Пример:
@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
, похоже, не требуется.