如何使AngularJs http.put()和Spring控制器协同工作(不再有状态400错误)?

时间:2015-08-22 20:59:01

标签: java json angularjs spring spring-mvc

我正在用Spring学习AngularJs。我正在转换现有的Spring MVC服务器以使用Angular提供的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":"jerome@myemail.com","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对象。我以为我应该用包装器传递一些东西,所以我可以包含错误和消息。这必须是本土的吗?或者像SpringEntity这样的Spring方面会为我服务吗?

第三个问题:假设我应该使用像User这样的东西,而不是包装器。我用什么语法来发送用户对象的列表或数组?

非常感谢,杰罗姆。

修改

很抱歉改变了这么多。我找到了另一个用于JSON通信的Spring MVC包,并将我的问题改为使用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通信正在进行中。我一直得到&#34;请求方法&#39; PUT&#39;不支持 - 请求的资源不允许使用指定的HTTP方法。&#34;

在我的服务器中,我确实有一个映射:

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。 杰罗姆。

2 个答案:

答案 0 :(得分:0)

第一个问题

HTTP状态为400的响应是由不正确的内容类型引起的。

您可以将其更改为

l[7]

如果您只是省略内容类型,那就更好了。根据{{​​3}}文档:

  

{"Content-Type": "application/json"} (PUT请求的标头默认值)

     
      
  • $httpProvider.defaults.headers.put
  •   

我敢打赌,你的案例中的json-to-object转换是由类路径中的 Jackson 执行的。当您使用Content-Type: application/json发送请求时,$http不会处理该请求。来自MappingJackson2HttpMessageConverter javadoc:

  

默认情况下,此转换器支持application/x-www-form-urlencoded和   application/json。这可以通过设置来覆盖   application/*+json财产。

如果您使用 Jackson 1.x ,则MappingJackson2HttpMessageConverter对内容类型的行为类似。

第二个问题

如果要在supportedMediaTypes旁边返回一些错误,可以使用包装器。根据您的情况,您可能还需要查看MappingJacksonHttpMessageConverter@ExceptionHandler

第三个问题

只需返回User

答案 1 :(得分:0)

伙计,我讨厌这些细节。我的问题是由两件事引起的,一件简单。

首先,我的User对象,我之前没有打印的详细信息,有一些帮助函数,如&#34; isAdminRole()&#34;推荐用于Spring的Jackson JSON库转换为属性名称(&#34; adminRole&#34;)。入站没有setAdminRole(),所以Jackson库抛出异常:

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。从来没有见过这个。

其次,我的Angular控制器同时使用$ scope.myDataGet.fromServer和fromServers。一旦你看到它就会出现明显错字。使用fromServers版本意味着空白数据作为JSON发送到服务器,服务器拒绝修改后的版本,以及基于jQuery的.ajax()调用,发生400错误(语法无效)。

在这两者之间,我失去了一两天的工作。我非常感谢Constatine的回复和成千上万的StackOverflow条目的大量帮助,让我了解我需要启用调试日志记录。

我有一个例子在这里工作,现在我可以继续了。