【问题标题】:File Upload in AngularJS JSON Spring MVC application 400 Bad Request Required request part is not presentAngularJS JSON Spring MVC应用程序中的文件上传400错误请求所需的请求部分不存在
【发布时间】:2016-10-04 08:25:49
【问题描述】:

我们正在使用 AngularJS 1.5.8、Spring 3.2.17、Jackson 2.6.7;

我们需要使用 JSON DTO 对象来实现文件上传。 我们无法通过多种配置和方法看到文件上传成功,仅 DTO 作为 json 请求参数工作正常。

提前致谢!

bill_payment.html的sn-ps

<form name="billPaymentForm" enctype="multipart/form-data" ng-submit="onSaveIRFBillPayment()">
<!-- some more elements as part of billPaymentDTO -->
<td class="fielddata6">
<input type = "file" file-model = "attachments.depositSlipFile"/>
</td>

app.js

var app = angular.module('app', [ 'ngRoute', 'ngResource', 'billPaymentAppControllers', 'billPaymentAppServices' ]);
...

app.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]);
             });
          });
       }
    };
}]);

billPaymentControllers.js

var billPaymentAppControllers = angular.module('billPaymentAppControllers', [ 'billPaymentAppServices' ]);

billPaymentAppControllers.controller('billPaymentCtrl',['$routeParams', '$route', '$scope', '$location', '$http', '$window', 'BillPaymentService',  function($routeParams, $route, $scope, $location, $http, $window, BillPaymentService) { 
// many other functions

$scope.onSaveIRFBillPayment =function(){
BillPaymentService.saveBillPayment.saveBillPaymentDtls(
{
    billPaymentDTO : $scope.billPaymentDTO,
    depositSlipFile : $scope.attachments.depositSlipFile
},function(result) {
        console.log(result);
        if(result!=null && result.returnVal!=null && result.returnVal!="" && result.returnVal == "SUCCESS"){
        alert("Bill Payment Saved Successfully");
        } else {
        alert("Error while Saving Bill Payment, please contact IT team");
        return false;
    }
});

}

billPaymentServices.js

billPaymentAppServices.factory('BillPaymentService', function($resource, $http) {
    return{

        saveBillPayment : $resource('agreement/saveIRFBillPayment/', {}, {
            'saveBillPaymentDtls' : {
                method : 'POST',
                headers: {'Content-Type': undefined},
                //transformRequest: angular.identity,                
                transformRequest: function (data) {
                      var formData = new FormData();
                      console.log("data DTO: "+angular.toJson(data.billPaymentDTO));
                      formData.append('billPaymentDTO', angular.toJson(data.billPaymentDTO));                  
                    //console.log("data file Content: "+data.depositSlipFile);
                    //formData.append('billPaymentDTO', new Blob([angular.toJson(data.billPaymentDTO)], {
                    //type: "application/json"
                    //}));
                      formData.append("file", data.depositSlipFile);
                      return formData;
                },
                  transformResponse : function(data) {
                    console.log(data);
                    data = {"returnVal":data};
                    return data;
                }
            }
       })
    }
}

BillPaymentRestController.java

//@ExceptionHandler(Exception.class) 
/*** This signature is working for DTO object alone in request ***/
//@RequestMapping(value="/saveIRFBillPayment", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
//public @ResponseBody String saveIRFBillPayment(@RequestBody String billPaymentDTO,HttpServletRequest request) throws RatingsServiceException, Exception{ 

/*** tried without consumes attribute, without argument HttpServletRequest request ***/
//@RequestMapping(value="/saveIRFBillPayment", method = RequestMethod.POST)
//@ResponseBody String saveIRFBillPayment(@RequestPart("billPaymentDTO") String billPaymentDTO, @RequestPart("file") MultipartFile depositSlipFile) throws RatingsServiceException, Exception{

//public @ResponseBody String saveIRFBillPayment(@RequestParam String billPaymentDTO, @RequestParam("file") MultipartFile depositSlipFile, HttpServletRequest request) throws RatingsServiceException, Exception{

@RequestMapping(value="/saveIRFBillPayment", method = RequestMethod.POST, consumes = {"multipart/form-data"})
@ResponseBody String saveIRFBillPayment(@RequestPart("billPaymentDTO") String billPaymentDTO, HttpServletRequest request, @RequestPart("file") MultipartFile depositSlipFile) throws Exception{

    System.out.println("Data inside saveIRFBillPayment:"+billPaymentDTO);
    System.out.println("\nFile inside saveIRFBillPayment:"+depositSlipFile);
    ObjectMapper mapper = new ObjectMapper();
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
    mapper.setDateFormat(dateFormat);
    String status="Fail";
    try{
    BillPaymentDTO billPaymentDTOConverted = mapper.readValue(billPaymentDTO, BillPaymentDTO.class);
    File ExtractedDepositSlipFile = billPaymentDTOConverted.getDepositSlipFile();
    System.out.println("File exists Check: "+ExtractedDepositSlipFile.exists());

    //Call to some service
    status="SUCCESS";

    }
    catch (Exception e) {
        e.printStackTrace();
    }

    return status;
}

dipatcher-servlet.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

    <context:component-scan base-package="com.xxx.xxxxx.restController.addAgreement" />
    <tx:annotation-driven />
    <mvc:annotation-driven />

    <!--        Added by PV - Type conversion -->
    <bean id="jacksonMessageConverter"
        class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>


    <bean
        class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />

    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="messageConverters">
    <list>
          <ref bean="jacksonMessageConverter" />
    </list>
     </property>
    </bean>

    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="268435456" /> <!-- 256 megs -->
    </bean>

    <bean id="methodHandlerExceptionResolver" class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver">
        <property name="messageConverters">
        <list>
            <bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter" />
            <bean class="org.springframework.http.converter.FormHttpMessageConverter" />
            <bean class="org.springframework.http.converter.StringHttpMessageConverter" />
        </list>
        </property>
    </bean>
</beans>

请求头:

Request:              POST /RatingsBD/cc-app/agreement/saveIRFBillPayment HTTP/1.1
X-Requested-With:         XMLHttpRequest
Accept:                 application/json, text/plain, */*
Content-Type:  multipart/form-data; boundary=---------------------------7e01c61b10544

请求正文:

Blank! when DTO being sent alone, it has json string with boundary

响应标头:

Response:           HTTP/1.1 400 Bad Request

响应正文:

Required request part 'billPaymentDTO' is not present.

【问题讨论】:

  • formData.append('billPaymentDTO', angular.toJson(data.billPaymentDTO)); 不添加请求部分。请查阅FormData.append() 的文档。
  • 改变你的 formData.append('billPaymentDTO', angular.toJson(data.billPaymentDTO));转 JSON.stringify(data.billPaymentDTO)
  • 我们已经尝试将 formData.append('billPaymentDTO', JSON.stringify(data.billPaymentDTO));而不是 formData.append('billPaymentDTO', angular.toJson(data.billPaymentDTO));仍然收到相同的 400 Bad Request 和 Request Body 为空白
  • 我们注意到,如果仅单独发送 DTO,请求正文如下: ------------------------- ----7e02552210544 内容处置:表单数据; name="billPaymentDTO" {"irfBill":{"billingClient":{ ....}}} --------------------------- --7e02552210544-- 仍然相同的错误 400 所需的请求部分 'billPaymentDTO' 不存在。""
  • 请您发布您的 DTO 结构

标签: java angularjs json spring http-status-code-400


【解决方案1】:

你有没有尝试过这样的事情。

$resource(
  url,
  {},
  {
    upload: {
      method: 'POST',
      headers: {enctype:'multipart/form-data'}
    },
  }
)

【讨论】:

  • 已经尝试过 content-type,将尝试这个并让您知道
【解决方案2】:

有一个解决此问题的方法,尝试通过以下方式更改您的 $http 调用,方法是在表单数据中附加所有 billPaymentDTO 值以及文件和类似的控制器,包括请求的参数。

                   var formData= new FormData();

                   formData.append('id', data.billPaymentDTO.ID);
                   formData.append('contactNumber', data.billPaymentDTO.number);
                   //add all the billPaymentDTO variables as mentioned above
                   formData.append("file", data.depositSlipFile);
                   var uploadUrl = $rootScope.BASE_URL + "agreement/saveIRFBillPayment";
                   $http.post(uploadUrl, formData, {
                       transformRequest: angular.identity,
                       headers: {
                           'Content-Type': undefined,
                           'Accept': 'application/json'
                       }
                   }).success(function(data) {
                   //do something after success
                  });

在 JAVA 端的控制器中

 @RequestMapping(value="/saveIRFBillPayment", method = RequestMethod.POST)
        @ResponseBody String saveIRFBillPayment(HttpServletRequest request, HttpServletResponse response,
                               @RequestParam(value="file") MultipartFile document,
                               @RequestParam("id") Long id,
                               @RequestParam("contactNumber") String contactNumber,
//similar way add all the attributes of billPaymentDTO here as parameter with required datatypes
                              ) { }

【讨论】:

  • @ng-10 :) 不幸的是它没有用,有同样的问题,如果只发送 DTO,请求工作正常,只有在请求 FormData 中附加文件或在请求中只发送文件时才会出错;上面的代码对你有用吗?
  • 是的,它确实有效!您是否实现了我在代码 sn-p 中显示的方式?您可以发布您更改的代码吗?
猜你喜欢
  • 2017-10-19
  • 2016-03-23
  • 2019-02-08
  • 2017-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-05
  • 2017-04-06
相关资源
最近更新 更多