问题
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.
回答1:
Have you tried something like this.
$resource(
url,
{},
{
upload: {
method: 'POST',
headers: {enctype:'multipart/form-data'}
},
}
)
回答2:
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
) { }
来源:https://stackoverflow.com/questions/39847532/file-upload-in-angularjs-json-spring-mvc-application-400-bad-request-required-re