Я изучаю AngularJs с весной. Я конвертирую существующий сервер Spring MVC для работы с JSON с поддержкой углов.
Выполнение GET было довольно простым, взломав код учебника. Выполнение PUT доказывает сложность. Я в основном получаю статус 400 (синтаксически неверно). Вместо того, чтобы помогать, я решил попросить совета.
Вот часть моего контроллера Spring:
@RequestMapping(value = "/json/{id}", method = RequestMethod.GET)
public @ResponseBody User getJEdit(@PathVariable("id") Long id) {
[snip]
User user = userService.get(id);
[snip]
return user;
}
@RequestMapping(value = "/json/{id}", method = RequestMethod.PUT)
public @ResponseBody User putJEdit(@RequestBody User userAttribute, @PathVariable("id") Long id) {
[snip]
}
Вот код контроллера AngularJs:
angular.module("myapp", [])
.controller("MyController", function($scope, $http) {
$scope.myDataGet = {};
$scope.myDataGet.doClickGet = function(item, event) {
var responsePromise = $http.get("/exchangeboard/admin/user/json/1");
responsePromise.success(function(data, status, headers, config) {
$scope.myDataGet.fromServer = data;
});
responsePromise.error(function(data, status, headers, config) {
alert("AJAX failed!");
});
};
$scope.myDataPut = {};
$scope.myDataPut.doClickPut = function(item, event) {
var responsePromise = $http.put("/exchangeboard/admin/user/json/1",
$scope.myDataGet.fromServer, {contentType: "application/x-www-form-urlencoded"});
responsePromise.success(function(data, status, headers, config) {
$scope.myDataPut.fromServer = data;
});
responsePromise.error(function(data, status, headers, config) {
alert("AJAX failed!");
});
}
});
Ответ от GET работает просто отлично (одна строка, сломанная для отображения):
{"id":1,"orgId":23,"name":"admin","password":"XXX",
"role":"ROLE_ADMIN","fullName":"Jerome","phone":"",
"email":"[email protected]","preferredContactMethod":"E",
"inactiveDate":null,"orgName":"Org 2 receiver","donor":false,
"adminRole":true,"inactiveDateString":""}
Я обернусь и отправлю это обратно на сервер. Я получаю эту ошибку:
<body>
<h1>HTTP Status 400 - </h1>
<HR size="1" noshade="noshade">
<p><b>type</b> Status report</p>
<p><b>message</b> <u></u></p><p><b>description</b> <u>The request sent by the client was syntactically incorrect.</u></p>
<HR size="1" noshade="noshade">
<h3>VMware vFabric tc Runtime 2.9.5.SR1/7.0.50.C.RELEASE</h3>
</body>
Код сервера putJEdit() не связывается - точки останова не попадают.
Я думаю, что ответ должен иметь правильный тип контента, но что?
Второй вопрос: предположим, что сервер хочет проверить все. Я передаю объект User. Я думаю, что я должен обойти что-то с помощью обертки, поэтому я могу включать ошибки и сообщения. Должно ли это быть доморощенным? Или что-нибудь на стороне Весны, как ResponseEntity, служит мне?
Третий вопрос: предположим, что я должен использовать что-то вроде User, а не обертку. Какой синтаксис я использую для отправки списка или массива объектов User?
Большое спасибо, Джером.
РЕДАКТИРОВАТЬ:
Извините, что меня так сильно изменили. Я нашел еще один пакет Spring MVC, который я использовал для связи JSON, и изменил мою проблему, чтобы использовать ResponseEntity. Это дает мне место для пользовательских статусов и сообщений. Тем не менее, у меня все еще нет успеха. Моя секция контроллера Java:
@RequestMapping(value = "/json/{id}", method = RequestMethod.GET, produces="application/json")
@ResponseBody
public ResponseEntity<User> getJEdit(@PathVariable("id") Long id) {
[snip]
return new ResponseEntity<User>(user, HttpStatus.OK);
}
@RequestMapping(value = "/json/{id}", method = RequestMethod.PUT, consumes = "application/json", produces="application/json")
@ResponseBody
public ResponseEntity<User> putJEdit(@RequestBody User userAttribute, @PathVariable("id") Long id) {
[snip]
return new ResponseEntity<User>(user, HttpStatus.OK);
}
Мой модуль AngularJs:
angular.module("myapp", []).controller("MyController", function($scope, $http) {
$http.defaults.useXDomain = true;
$scope.myDataGet = {};
$scope.myDataGet.doClickGet = function(item, event) {
var responsePromise = $http.get("/exchangeboard/admin/user/json/1");
responsePromise.success(function(data, status, headers, config) {
$scope.myDataGet.fromServer = data;
});
responsePromise.error(function(data, status, headers, config) {
alert("AJAX failed!");
});
};
$scope.myDataPut = {};
$scope.myDataPut.doClickPut = function(item, event) {
var responsePromise = $http.put("/exchangeboard/admin/user/json/1", $scope.myDataGet.fromServers, {headers: {'Content-Type': 'application/json'}});
responsePromise.success(function(data, status, headers, config) {
$scope.myDataPut.fromServer = data;
});
responsePromise.error(function(data, status, headers, config) {
alert("AJAX failed!");
});
};
});
GET всегда преуспевает. Это означает, что моя базовая связь Spring происходит нормально. Я последовательно получаю "Метод запроса" PUT "не поддерживается. Указанный HTTP-метод не разрешен для запрашиваемого ресурса".
На моем сервере у меня есть сопоставление:
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
- Mapped "{[/admin/user/json/{id}],methods=[PUT],params=[],headers=[],consumes=[application/json],produces=[application/json],custom=[]}"
onto public org.springframework.http.ResponseEntity<mystuff.domain.User> mystuff.controller.UserController.putJEdit(mystuff.domain.User,java.lang.Long)
Поэтому я не знаю, что я делаю неправильно. Если я изменю все, чтобы использовать POST вместо PUT, я все равно получаю то же самое 405. Джером.
Человек, я ненавижу эти подробности. Мои проблемы вызваны двумя вещами, одним простым.
Во-первых, мой объект User, подробности, для которого я не печатал ранее, имеют некоторые вспомогательные функции, такие как "isAdminRole()", что библиотека Jackson JSON, рекомендованная для использования Spring, преобразуется в имена атрибутов ("adminRole"). Входящий нет setAdminRole(), поэтому библиотека Джексона выдает исключение:
org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Unrecognized field "adminRole" (Class mystuff.domain.User), not marked as ignorable
Об этом сообщается как ошибка 405. 405 не всегда для вопросов CORS!
Я получил подсказку отсюда и там, чтобы включить отладку в log4j, org.springframework.web установлен в DEBUG. Никогда не видел бы этого иначе.
Во-вторых, мой угловой контроллер использует как $ scope.myDataGet.fromServer, так и fromServers. Очевидная опечатка, как только вы ее увидите. Использование версии fromServers означало, что пустые данные были отправлены как JSON на сервер, который отклонил пересмотренную версию, и вызовы.ajax() на основе jQuery с ошибкой 400 (недопустимый синтаксис).
Между этими двумя я потерял день или два работы. Я очень ценю ответы Constatine и огромную помощь тысяч записей StackOverflow, которые позволяют мне понять, что мне нужно включить ведение журнала отладки.
У меня есть один пример, работающий здесь, и теперь я могу продолжить.
Первый вопрос
Ответ с HTTP-статусом 400 вызван неправильным типом содержимого.
Вы можете изменить его на
{"Content-Type": "application/json"}
Еще лучше, если вы просто опустите тип контента вообще. Согласно документации http:
$httpProvider.defaults.headers.put
(значения по умолчанию для запросов PUT)
Content-Type: application/json
Бьюсь об заклад, что преобразование json-to-object в вашем случае выполняется Jackson в пути к классам. Когда вы отправляете запрос с application/x-www-form-urlencoded
, MappingJackson2HttpMessageConverter
не обрабатывает его. Из MappingJackson2HttpMessageConverter
javadoc:
По умолчанию этот конвертер поддерживает
application/json
иapplication/*+json
. Это можно переопределить, установив свойствоsupportedMediaTypes
.
Если вы используете Jackson 1.x, поведение MappingJacksonHttpMessageConverter
отношении типов контента аналогично.
Второй вопрос
Использование обертки прекрасно, если вы хотите вернуть некоторые ошибки вместе с User
. В зависимости от вашего сценария вы можете также взглянуть на @ExceptionHandler
и @ControllerAdvice
.
Третий вопрос
Просто @ResponseBody List<User>
.