【问题标题】:how to pass JSON object as a PathVariable to spring controller如何将 JSON 对象作为 PathVariable 传递给 spring 控制器
【发布时间】:2018-11-30 06:55:28
【问题描述】:

我正在使用 angularjs 开发 Spring 应用程序。我想将 JSON 对象作为 @PathVariable 传递给 spring 控制器,但是使用下面的代码,当将 JSON 对象作为 PathVariable 传递时,它没有命中 spring 控制器,也没有显示任何错误。任何输入?

示例代码: js:

myApp.controller('passJSONTestController', function ($rootScope, $scope, MyService) {
     $scope.submitdata=function(){
        $scope.myJSONData = [
            {   'name':$scope.name,
                'sinNumber': $scope.sinNo,
                'status': $scope.status,
                'message':$scope.message,
            }
        ];
        var fd=new FormData();
        angular.forEach($scope.files,function(file){
            console.log("file " + file);
            fd.append('file',file);
        });
        MyService.sendJSON($scope.myJSONData,fd).then(
            function (response) {
                //
            },
            function (errResponse) {
             }
        );
    }
});

MyService.js

myService.sendJSON = function (myJSONData,fd) {
         var deferred = $q.defer();
        var myUrl = applnURL + '/dataStack/' + myJSONData + '/getAllDataInfo.form';
          var config = {
            transformRequest: angular.identity,
             headers : {
                'Content-Type': undefined
            }
        }
         $http.post(repUrl, fd, config ).then(function (response) {
        }, function (response) {
         });
         return deferred.promise;
     }

弹簧控制器:

@Controller
@RequestMapping("/dataStack")
public class GetData {
 @RequestMapping(value = "/{myJSONData}/getAllDataInfo", method = RequestMethod.POST)
    public
    @ResponseBody
    String sendInfo(@RequestParam("file") List<MultipartFile> multiPartFileList,@PathVariable("myJSONData") List<MyDTO> myDTO){                          
        System.out.println("In Spring controller");
   }

为什么传递的请求没有命中spring控制器? PS:如果我删除 spring 控制器中的路径变量并将其从 mySerivce.js 中删除,那么它正在命中 spring 控制器。

-------------已编辑(更新代码)------------- 我添加了以下类:

@Configuration
public class MultiFileResolverConfig {
    @Bean(name = "multipartResolver")
    public MultipartResolver multipartResolver() {
        System.out.println("--In configuration file multipartResolver--");
        return new CommonsMultipartResolver();
    }
}

spring-servlet.xml 我在 sprig-servlet.xml 配置文件下面添加了&lt;bean&gt;

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="10000000"/>
</bean>

html代码:

<html>
..elements for name,sinNumber,status,message
  <input type = "file"  name="file" file-model="file" multiple/>
..//submit button
</html>

js代码:

 myApp.directive('fileModel', ['$parse', function ($parse) {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            var model = $parse(attrs.fileModel);
            var modelSetter = model.assign;

            element.bind('change', function(){
                scope.$apply(function(){
                    modelSetter(scope, element[0].files[0]);
                });
            });
        }
    };
}]);

    myApp.controller('passJSONTestController', function ($rootScope, $scope, MyService) {
         $scope.submitdata=function(){
            $scope.myJSONData = [
                {   'name':$scope.name,
                    'sinNumber': $scope.sinNo,
                    'status': $scope.status,
                    'message':$scope.message,
                }
            ];
            var fd=new FormData();
            angular.forEach($scope.files,function(file){
                console.log("file " + file);
                fd.append('file',file);
            });
            fd.append("json",$scope.myJSONData);
            MyService.sendJSON(fd).then(
                function (response) {
                    //
                },
                function (errResponse) {
                 }
            );
        }
    });

service.js

myService.sendJSON = function (fd) {
         var deferred = $q.defer();
        var myUrl = applnURL + '/dataStack/getAllDataInfo.form';
          var config = {
            transformRequest: angular.identity,
             headers : {
                'Content-Type': undefined
            }
        }
         $http.post(myUrl, fd, config ).then(function (response) {
        }, function (response) {
         });
         return deferred.promise;
     }

弹簧控制器:

@Controller
@RequestMapping("/dataStack")
public class GetDataController{
    @RequestMapping(value = "/getAllDataInfo", method = RequestMethod.POST)
    public @ResponseBody
    String uploadMultipleFileHandler(MultipartHttpServletRequest req) {

        System.out.println("in spring upload multiple files");
        List<MultipartFile> multiPartFileList = req.getFiles("file");
        System.out.println("in multiPartFileList " + multiPartFileList.size());//size is always zero
        String[] json = (String[]) req.getParameterMap().get("json");//getting the values submitted
        //code here..

我正在获取 json 对象的值,但无法获取文件详细信息。 multiPartFileList.size() 的大小为零。我尝试仅添加类 MultiFileResolverConfig 并删除 spring-servlet.xml 中的 &lt;bean&gt; 声明,但文件详细信息仍未传递给 spring 控制器。

【问题讨论】:

  • 为什么你通过带有变量的json对象,你应该去@RequestParam或者最好的方法是使用POST并通过requestbody
  • 我尝试使用 post 并通过 RequestBody,如果您在上面的代码中看到我的 post 方法,我正在传递 url、fd、config 信息,并且当我将此 Json 对象添加为其他参数并修改 spring 控制器以接受时RequestBody 它仍然无法识别弹簧控制器...
  • 您也必须更改请求映射 url。

标签: java json spring angular


【解决方案1】:

2018 年 6 月 22 日更新

当涉及到多部分请求时,请注意 Spring Boot 和 Spring MVC 的工作方式不同。默认情况下,Spring MVC 提供 MultipartResolver,因此无法解析多部分请求。您必须在 ApplicationContext 中提供一个“multipartResolver”bean。但是,Spring MVC 确实为此提供了两种实现; StandardServletMultipartResolverCommonsMultipartResolver。将其中任何一个配置到您的应用程序上下文中都可以。例如:

@Configuration
public class SomeConfig {
   @Bean
   public MultipartResolver multipartResolver() {
      return new CommonsMultipartResolver();
   }
}

注意:bean 的名称很重要。

另一方面,Spring Boot 将代表您自动配置 StandardServletMultipartResolver 的实例,因此能够“开箱即用”地解决多部分请求。

原答案

您也应该使用 FormData 对象传递附加数据。

更改您的客户端代码以附加附加数据:

myApp.controller('passJSONTestController', function ($rootScope, $scope, MyService) {
     $scope.submitdata=function(){
        $scope.myJSONData = [
            {   'name':$scope.name,
                'sinNumber': $scope.sinNo,
                'status': $scope.status,
                'message':$scope.message,
            }
        ];
        var fd=new FormData();
        angular.forEach($scope.files,function(file){
            console.log("file " + file);
            fd.append('file',file);
        });

        // do this instead
        data.append('json', JSON.stringify($scope.myJSONData);
        ...

在您的控制器中修复请求映射并使其接受MultipartHttpServletRequest 参数而不是List&lt;MultipartFile&gt;

@Controller
@RequestMapping("/dataStack")
public class GetData {
 @RequestMapping(value = "/getAllDataInfo", method = RequestMethod.POST)
    public
    @ResponseBody
    String sendInfo(MultipartHttpServletRequest req){        

       List<MultipartFile> multiPartFileList = req.getFiles("file");
       ...

       String[] json = req.getParameterMap().get("json");

       // Jackson deserialization...but you could use any...Gson, etc
       ObjectMapper mapper = new ObjectMapper();
       TypeReference<Map<String,String>> typeRef = new TypeReference<Map<String,String>>() {};
       Map<String,String> data = mapper.readValue(json[0], typeRef);
       ...

确保更新 MyService 以发布到新的请求映射:

myService.sendJSON = function (fd) {
         var deferred = $q.defer();
         var myUrl = applnURL + '/dataStack/getAllDataInfo.form';
        ...

我认为这应该为你做。

HTH

【讨论】:

  • 我按照您的建议尝试,但它不支持 getParameterMap - 它说无法解析方法 getParameterMap..
  • 我已将 MyService 修改为: $http.post(repUrl, formData, { transformRequest: function(data, headersGetterFunction) { return data; }, headers: {'Content-Type': undefined, } }).then(function (response) { console.log("response" + response); },它正在命中 spring 控制器,但 spring 控制器中的 multiPartFileList 大小为零。即,List multiPartFileList = req .getFiles("file"); //大小为零,文件信息不存在。任何输入都会有帮助..
  • @Paul Warren - 我在上面尝试使用 spring 和 angularjs 的代码,正如用户 nan 提到的,spring 控制器中的 multiPartFileList 大小为零。在传递请求和在 spring 控制器中我们是否需要包含任何特殊的标头?
  • @user3684675 请查看我的更新答案。让我知道这是否适合您。
  • @PaulWarren- 感谢您的更新..我已经按照您上面的建议进行了尝试,但仍然无法在 spring 控制器中获取附件的详细信息。我在上面的帖子的编辑版本中添加了完整的更新代码(---EDITED(更新代码)-----)。任何输入都会有所帮助..我对此非常困惑..我正在使用带有 angularjs 的 spring4(spring mvc)。
【解决方案2】:
  1. 在您的客户端代码中,即 MyService.js 发送正确的 Content-Type,在您的情况下是 application/json

    headers : {
        'Content-Type': application/json
    }
    
  2. 在服务器端,即 spring 控制器:,让您的请求映射器了解传入请求的数据类型:

    @RequestMapping(value = "/{myJSONData}/getAllDataInfo", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON)

【讨论】:

  • 我需要将文件信息以及 JSON 对象传递给 spring 控制器。要传递文件信息,我需要在 MyService.js 中设置标题:{'Content-Type': undefined },正如你所说的发送 json 对象,标题应该是 application/json 但它不允许文件发送..关于如何将文件信息以及 JSON 对象发送到 spring 控制器的任何输入。我可以将 json 转换为字符串并作为 PathVariable 发送,但问题是当对象太长或者它包含特殊字符时,它不允许作为 PathVariable 发送..
  • @PaulWarren - 弹簧控制器中的文件大小为零,弹簧控制器中的 multiPartFileList 为零,我是否需要在弹簧控制器中包含任何头信息才能将文件信息从角度传递给弹簧控制器,请咨询..谢谢
【解决方案3】:

可以以Object(DTO)的形式发送

如下图

var createEvaluationRequestObject = {"test":"Value1","test2":"value2"};
var createEvaluationRequest       = JSON.stringify (createEvaluationRequestObject);

试试这个,应该可以的

【讨论】:

  • 我可以通过转换 JSON>Stringify 来发送,但问题是我的 JSON 对象可能太长,其中包含特殊字符。所以它不允许我作为 PathVariable 发送。当 JSON 没有特殊字符时,我可以成功地将它作为字符串发送到 spring 控制器。但在我的情况下,它可能包含许多特殊字符,并且 JSON 中的值可能很长。我可以将文件信息和 JSON 对象作为 RequestParam 和 RequestBody 发送..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-11
  • 1970-01-01
  • 2011-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多