混合 POST 从 AngularJS 提交到 Spring RestController

Mixed POST submit from AngularJS to Spring RestController

基本上,我希望能够 post 包含一些字段 (JSON) 和附件(多部分)的表单。 以下是实际工作的代码,问题是我不喜欢它所以它主要是因为变通方法而起作用。

Angular 控制器

$http({
    method: 'POST',
    url: 'rest/store/logo',
    headers: {'Content-Type': undefined },
    transformRequest: function (data) {
        var formData = new FormData();
        //need to convert our json object to a string version of json otherwise the browser will do a 'toString()' on the object which will result in the value '[Object object]' on the server.
        formData.append("store", angular.toJson(data.store));
        formData.append("file", data.file);
        return formData;
    },
    data: { store: $scope.selectedStore, file: $scope.myFile } //not important but $scope.myFile comes from a directive: http://jsfiddle.net/JeJenny/ZG9re/
});

Spring 控制器

@RequestMapping(value = "/logo", method = RequestMethod.POST)
public @ResponseBody void updateLogo(HttpServletRequest request, @RequestParam(value = "store", required = false) String store, @RequestPart("file") MultipartFile file) {
    System.err.println("store: " + store); //the JSON 
    StoreEditTO storeEditTO = new Gson().fromJson(store, StoreEditTO.class);
    System.err.println("storeEditTO: " + storeEditTO);
}

所以,虽然这可行,但我确信有两件事可以简化:

  1. Angular:还不错,但代码似乎更复杂,应该是
  2. Spring:这是最令人不安的;文件没问题,但我需要将 store 的参数类型设置为 String 或 Spring 会给我一个 'no matching editors or conversion strategy found'。不知何故,请求参数未被识别为 JSON,我猜这是因为将内容类型设置为未定义,但如果我不这样做,我会得到:'org.springframework.web.multipart.MultipartException: The current request is not a multipart request'?

顺便说一句,将两者分开发布就可以了。 JSON 被转换为正确的类型并且文件被接收。到目前为止,我已经花了几个小时让混合模式(以一种干净的方式)工作,但运气不佳...

多亏了上面提到的 comment/link 我让它工作得很干净。我其实已经很接近了,但错过了 {type: "application/json"}.

完整的解决方案:

@RequestMapping(value = "/logo", method = RequestMethod.POST, consumes = {"multipart/form-data"})
public @ResponseBody void updateLogo(@RequestPart(value = "store") StoreEditTO store, @RequestPart("file") MultipartFile file) {
}

$http({
    method: 'POST',
    url: 'rest/store/logo',
    headers: {'Content-Type': undefined },
    transformRequest: function (data) {
        var formData = new FormData();

        formData.append('store', new Blob([angular.toJson(data.store)], {
            type: "application/json"
        }));
        formData.append("file", data.file);
        return formData;
    },
    data: { store: $scope.selectedStore, file: $scope.myFile }

}).
success(function (data, status, headers, config) {
});