Как заставить AngularJs http.put () и Spring контроллер работать вместе (больше нет ошибок status 400)?

0

Я изучаю 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. Джером.

Теги:
spring
spring-mvc

2 ответа

0
Лучший ответ

Человек, я ненавижу эти подробности. Мои проблемы вызваны двумя вещами, одним простым.

Во-первых, мой объект 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, которые позволяют мне понять, что мне нужно включить ведение журнала отладки.

У меня есть один пример, работающий здесь, и теперь я могу продолжить.

0

Первый вопрос

Ответ с 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>.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню