1

We are using AngularJS 1.5.8 , Spring 3.2.17, Jackson 2.6.7;

we need to implement file upload with a JSON DTO object. We are unable to see success with file upload with several configurations and approaches, DTO alone as json request parameter is working fine.

Thanks in advance!

snippets of bill_payment.html

<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 header:

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

Request Body :

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

Response Header:

Response:           HTTP/1.1 400 Bad Request

Response Body :

Required request part 'billPaymentDTO' is not present.
7
  • formData.append('billPaymentDTO', angular.toJson(data.billPaymentDTO)); doesn't add a request part. Please consult the documentation for FormData.append(). Commented Oct 4, 2016 at 8:43
  • Change your formData.append('billPaymentDTO', angular.toJson(data.billPaymentDTO)); to JSON.stringify(data.billPaymentDTO) Commented Oct 4, 2016 at 8:58
  • we have tried putting formData.append('billPaymentDTO', JSON.stringify(data.billPaymentDTO)); instead of formData.append('billPaymentDTO', angular.toJson(data.billPaymentDTO)); still getting same 400 Bad Request and Request Body is going as blank Commented Oct 4, 2016 at 9:34
  • We have noticed that if only DTO is being sent alone, request body has below: -----------------------------7e02552210544 Content-Disposition: form-data; name="billPaymentDTO" {"irfBill":{"billingClient":{ ....}}} -----------------------------7e02552210544-- still same error 400 Required request part 'billPaymentDTO' is not present."" Commented Oct 4, 2016 at 9:42
  • Please can you post your DTO structure Commented Oct 4, 2016 at 10:21

2 Answers 2

1

Have you tried something like this.

$resource(
  url,
  {},
  {
    upload: {
      method: 'POST',
      headers: {enctype:'multipart/form-data'}
    },
  }
)
Sign up to request clarification or add additional context in comments.

1 Comment

have tried content-type, will try this and let you know
0

There is a work around for this issue,try changing your $http call in below way by appending all your billPaymentDTO values in the form data along with file and similar at your controller include the params as requested.

                   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
                  });

In your Controller at JAVA side

 @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
                              ) { }

2 Comments

@ng-10 :) unfortunately it did not work, having same issue, if send just DTO, request works fine, get error only when append file in the request FormData or send only file in request; was above code worked for you?
Yes it definitely works ! Did you implement the way I showed in the code snippet ? Can u post your changed code ?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.