I have a Java Spring MVC Web application as server. And AngularJS based application as client.
In AngularJS, I have to upload a file and send to server.
Here is my html
<form ng-submit="uploadFile()" class="form-horizontal" enctype="multipart/form-data">
<input type="file" name="file" ng-model="document.fileInput" id="file" onchange="angular.element(this).scope().setTitle(this)" />
<input type="text" class="col-sm-4" ng-model="document.title" id="title" />
<button class="btn btn-primary" type="submit">
Submit
</button>
</form>
Here is my UploadController.js
'use strict';
var mainApp=angular.module('mainApp', ['ngCookies']);
mainApp.controller('FileUploadController', function($scope, $http) {
$scope.document = {};
$scope.setTitle = function(fileInput) {
var file=fileInput.value;
var filename = file.replace(/^.*[\\\/]/, '');
var title = filename.substr(0, filename.lastIndexOf('.'));
$("#title").val(title);
$("#title").focus();
$scope.document.title=title;
};
$scope.uploadFile=function(){
var formData=new FormData();
formData.append("file",file.files[0]);
$http({
method: 'POST',
url: '/serverApp/rest/newDocument',
headers: { 'Content-Type': 'multipart/form-data'},
data: formData
})
.success(function(data, status) {
alert("Success ... " + status);
})
.error(function(data, status) {
alert("Error ... " + status);
});
};
});
It is going to the server. Here is my DocumentUploadController.java
@Controller
public class DocumentUploadController {
@RequestMapping(value="/newDocument", headers = "'Content-Type': 'multipart/form-data'", method = RequestMethod.POST)
public void UploadFile(MultipartHttpServletRequest request, HttpServletResponse response) {
Iterator<String> itr=request.getFileNames();
MultipartFile file=request.getFile(itr.next());
String fileName=file.getOriginalFilename();
System.out.println(fileName);
}
}
When I run this I get the following exception
org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; nested exception is org.apache.commons.fileupload.FileUploadException: the request was rejected because no multipart boundary was found] with root cause
org.apache.commons.fileupload.FileUploadException: the request was rejected because no multipart boundary was found
at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.<init>(FileUploadBase.java:954)
at org.apache.commons.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:331)
at org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:351)
at org.apache.commons.fileupload.servlet.ServletFileUpload.parseRequest(ServletFileUpload.java:126)
at org.springframework.web.multipart.commons.CommonsMultipartResolver.parseRequest(CommonsMultipartResolver.java:156)
at org.springframework.web.multipart.commons.CommonsMultipartResolver.resolveMultipart(CommonsMultipartResolver.java:139)
at org.springframework.web.servlet.DispatcherServlet.checkMultipart(DispatcherServlet.java:1047)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:892)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:920)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:827)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:801)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
In my applicationContext.xml, I have mentioned
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="100000" />
</bean>
I am using
spring - 3.2.1.RELAESE
commons-fileupload - 1.2.2
commons-io - 2.4
How to solve this?
It would be great if anyone tel me how to send file and other formdata from angularJS and get it in server.
UPDATE 1
@Michael : I can see this only in the console, when I click submit.
POST http://localhost:9000/serverApp/rest/newDocument 500 (Internal Server Error) angular.js:9499
(anonymous function) angular.js:9499
sendReq angular.js:9333
$http angular.js:9124
$scope.uploadFile invoice.js:113
(anonymous function) angular.js:6541
(anonymous function) angular.js:13256
Scope.$eval angular.js:8218
Scope.$apply angular.js:8298
(anonymous function) angular.js:13255
jQuery.event.dispatch jquery.js:3074
elemData.handle
My server is running in other port 8080. I am uisng yeoman,grunt and bower. So thin gruntfile.js I have mentioned the server port. So it goes to server and running that and throws the exception
UPDATE 2
The boundary is not setting
Request URL:http://localhost:9000/serverApp/rest/newDocument
Request Method:POST
Status Code:500 Internal Server Error
Request Headers view source
Accept:application/json, text/plain, */*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Content-Length:792
Content-Type:multipart/form-data
Cookie:ace.settings=%7B%22sidebar-collapsed%22%3A-1%7D; isLoggedIn=true; loggedUser=%7B%22name%22%3A%22admin%22%2C%22password%22%3A%22admin23%22%7D
Host:localhost:9000
Origin:http://localhost:9000
Referer:http://localhost:9000/
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
X-Requested-With:XMLHttpRequest
Request Payload
------WebKitFormBoundaryCWaRAlfQoZEBGofY
Content-Disposition: form-data; name="file"; filename="csv.csv"
Content-Type: text/csv
------WebKitFormBoundaryCWaRAlfQoZEBGofY--
Response Headers view source
connection:close
content-length:5007
content-type:text/html;charset=utf-8
date:Thu, 09 Jan 2014 11:46:53 GMT
server:Apache-Coyote/1.1
A new attribute "maxSwallowSize" is the key to deal this situation. It should happen when you upload a file which is larger than 2M. Because the 2M is the default value of this new attribute .
Constructor for use as bean. Determines the servlet container's temporary directory via the ServletContext passed in as through the ServletContextAware interface (typically by a WebApplicationContext).
public interface MultipartResolver. A strategy interface for multipart file upload resolution in accordance with RFC 1867. Implementations are typically usable both within an application context and standalone.
I faced the same issue and encountered the same issue even after updating the transformRequest. 'Some how, the header boundary doesn't seem to have set correctly.
Following http://uncorkedstudios.com/blog/multipartformdata-file-upload-with-angularjs, the problem is resolved. Extract from the location....
By setting ‘Content-Type’: undefined, the browser sets the Content-Type to multipart/form-data for us and fills in the correct boundary. Manually setting ‘Content-Type’: multipart/form-data will fail to fill in the boundary parameter of the request.
Not sure if this helps any one but perhaps makes it easy for people looking at this post... At least, it makes it less difficult.
I have had the same problem and found a complete solution to send both json and file from angular based page to a Spring MVC method.
The main problem is the $http which doesn't send the proper Content-type header (I will explain why).
To send both json and file we need to send a multipart/form-data, which means "we send different items in the body separated by a special separator". This special separator is called "boundary", which is a string that is not present in any of the elements that are going to be sent.
The server needs to know which boundary is being used so it has to be indicated in the Content-type header (Content-Type multipart/form-data; boundary=$the_boundary_used).
So... two things are needed:
Example of a good request:
Content-Type multipart/form-data; boundary=---------------------------129291770317552
Which is telling the server "I send a multipart message with the next separator (boundary): ---------------------------129291770317552
-----------------------------129291770317552 Content-Disposition: form-data; name="clientInfo"
{ "name": "Johny", "surname":"Cash"}
-----------------------------129291770317552
Content-Disposition: form-data; name="file"; filename="yourFile.pdf"
Content-Type: application/pdf
%PDF-1.4
%õäöü
-----------------------------129291770317552 --
Where we are sending 2 arguments, "clientInfo" and "file" separated by the boundary.
If the request is sent with $http, the boundary is not sent in the header (point 1), so Spring is not able to process the data (it doesn't know how to split the "parts" of the request).
The other problem is that the boundary is only known by the FormData... but FormData has no accesors so it's impossible to know which boundary is being used!!!
Instead of using $http in js you should use standard XMLHttpRequest, something like:
//create form data to send via POST
var formData=new FormData();
console.log('loading json info');
formData.append('infoClient',angular.toJson(client,true));
// !!! when calling formData.append the boundary is auto generated!!!
// but... there is no way to know which boundary is being used !!!
console.log('loading file);
var file= ...; // you should load the fileDomElement[0].files[0]
formData.append('file',file);
//create the ajax request (traditional way)
var request = new XMLHttpRequest();
request.open('POST', uploadUrl);
request.send(formData);
Then, in your Spring method you could have something like:
@RequestMapping(value = "/", method = RequestMethod.POST)
public @ResponseBody Object newClient(
@RequestParam(value = "infoClient") String infoClientString,
@RequestParam(value = "file") MultipartFile file) {
// parse the json string into a valid DTO
ClientDTO infoClient = gson.fromJson(infoClientString, ClientDTO.class);
//call the proper service method
this.clientService.newClient(infoClient,file);
return null;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With