upload a file along with some data in struts - file

i want to upload an image file along with some data through a struts form, process data , and store that image in DB
i have created a form for it , defined action for uploading file in struts.xml file , but when the control comes in java method ,getting null in the File type variable, please help on it.
code in struts.xml :
<action name="uploadFile" class="org.ui.LogActivityAction"
method="uploadFile">
<interceptor-ref name="fileUpload">
<param name="fileUpload.maximumSize">10485760</param>
<param name="fileUpload.allowedTypes">text/plain,image/jpg</param>
</interceptor-ref>
<interceptor-ref name="defaultStack"/>
<result name="success">/user/activity/upload-card.jsp</result>
<result name="error">/user/activity/upload-card.jsp</result>
</action>
ajax used for sending data to action :
function saveSalesUserActivity(card) {
var isValidForm = jQuery('#dailyActivity').valid();
isValidForm = jQuery('#dailyActivity').valid();
if (!isValidForm) {
return;
}
if (isValidForm) {
jQuery.blockUI({
message: "<strong>" + messages("mis.common.wait") + "</strong>"
});
jQuery.ajax({
type: "POST",
url: "/sales/user/logactivity/saveactivity.action?businessCard=" + card,
data: jQuery('#dailyActivity').serialize(),
success: function(response) {
jQuery("#miscontent").html(response);
},
error: function(response) {
jQuery("#miscontent").html(response);
}
});
jQuery.unblockUI();
}
jQuery.unblockUI();
}
through this when reaching in java method,I am not getting the value of File type variable( used 'businessCard' here)..
anyone help..

If you used jQuery('#dailyActivity').serialize(),
It it is not working for <input type'file'>
Have look at this jsFiddle Does not works
and this one .serialize()
Data from file select elements is not serialized.
To send <input type'file'> you may want to try this
var formData = new FormData($('form')[0]);
Have look at this https://stackoverflow.com/a/8758614/3425489

For uploading file using jQuery you have to use formdata
Working code for file uploading is below
$(document).on('click', '#upload', function(e) {
e.preventDefault();
var fd = new FormData();
var file = $('#my_file')[0].files[0];
fd.append('file', file);
fd.append('userId', $('#userid').val());
console.log("hi");
$.ajax({
url: 'UploadPic',
data: fd,
type: "POST",
contentType: false,
processData: false,
success: function(dd) {
alert("sucessfully Uploaded")
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="file" id="my_file">
<input type="hidden" id="userid" />
<input type="button" id="upload" value="Upload" />

Related

Back& File Upload Support - JSON

I'm currently trying to get the file upload working but hitting a problem in that the form is uploading the payload with multipart form data instead of a JSON object.
Back& will only accept a JSON object with filename and filedata inside, but I can't figure out how to accomplish this with ng-admin.
My code currently looks like this:
.uploadInformation( { 'url': BackandProvider.getApiUrl()+'/1/objects/action/games', 'params': {'name':'files'}, 'headers': { 'Content-Type': false }, 'data': data })
I see you are using BackandProvider so to bypass this you can implement the upload yourself.
From Backand docs
<body class="container" ng-app="app" ng-controller="DemoCtrl" ng-init="initCtrl()">
<h2>Backand Simple Upload File</h2>
<br/>
<form role="form" name="uploadForm">
<div class="row">
<img ng-src="" ng-show="imageUrl" />
<input id="fileInput" type="file" accept="*/*" ng-model="filename" />
<input type="button" value="x" class="delete-file" title="Delete file" ng-disabled="!imageUrl" ng-click="deleteFile()" />
</div>
</form>
</body>
// input file onchange callback
function imageChanged(fileInput) {
//read file content
var file = fileInput.files[0];
var reader = new FileReader();
reader.onload = function(e) {
upload(file.name, e.currentTarget.result).then(function(res) {
$scope.imageUrl = res.data.url;
$scope.filename = file.name;
}, function(err){
alert(err.data);
});
};
reader.readAsDataURL(file);
};
// register to change event on input file
function initUpload() {
var fileInput = document.getElementById('fileInput');
fileInput.addEventListener('change', function(e) {
imageChanged(fileInput);
});
}
// call to Backand action with the file name and file data
function upload(filename, filedata) {
// By calling the files action with POST method in will perform
// an upload of the file into Backand Storage
return $http({
method: 'POST',
url : Backand.getApiUrl() + baseActionUrl + objectName,
params:{
"name": filesActionName
},
headers: {
'Content-Type': 'application/json'
},
// you need to provide the file name and the file data
data: {
"filename": filename,
"filedata": filedata.substr(filedata.indexOf(',') + 1, filedata.length) //need to remove the file prefix type
}
});
};

C# with kendo ui - client send file to server

I'm trying to send a .xlsx file to my REST API using Kendo Ui. But I'm lost.
I was able to call my service, but I can't get the file. I believe I'm sending it wrong.
I don't need to save the file. I only need to read the .xlsx file to import the data to my database.
html (don't have a form):
<div>
<input name="files" id="files" type="file" />
<button id="importButton">Import</button>
</div>
js:
$("#files").kendoUpload({
async: {
autoUpload: true
},
select: onSelect
});
$("#importButton").kendoButton({
click: onImport
});
function onImport() {
var formData = new FormData();
jQuery.each(jQuery('#files')[0].files, function (i, file) {
formData.append('file-' + i, file);
});
$.ajax({
type: "POST",
url: url,
data: formData,
processData: false,
cache: false,
success: function (result) {
alert("Ok");
},
error: function (result) {
alert("Not Ok");
}
});
}
Server-side:
[HttpPost, Route("import")]
public void Import()
{
var streamProvider = new MultipartMemoryStreamProvider();
Request.Content.ReadAsMultipartAsync<MultipartMemoryStreamProvider>(streamProvider).ContinueWith((tsk) =>
{
foreach (HttpContent ctnt in streamProvider.Contents)
{
Stream stream = ctnt.ReadAsStreamAsync().Result;
// do something
}
});
}
Got it!
$("#files").kendoUpload({
async: {
withCredentials: false,
saveUrl: url,
autoUpload: true
},
select: onSelect
});
This answer helped me: Cross domain upload
#Brett was right, implement the kendUpload was the way.
I thought the Import button should do the magic, but I only need to use kendoUpload.
Thanks!!

Spring MultipartException: The current request is not a multipart request

I'm trying to upload a file with AngularJS and Spring controller.
The Angular controller looks like this:
$scope.uploadFile=function(){
var formData=new FormData();
formData.append("file",file.files[0]);
$http.post('/content-files/upload /', file.files[0], {
transformRequest: function(data, headersGetterFunction) {
return data; // do nothing! FormData is very good!
},
headers: {'Content-Type': undefined }
})
.success(function(){
console.log('Post Succeded !');
})
.error(function(){
console.log('Post Failed .');
});
}
I also try this:
var formData = new FormData();
formData.append('file',file.files[0]);
$http.post('/content-files/upload /', formData, {
headers: { 'Content-Type': undefined },
transformRequest: angular.identity
})
and the Spring controller looks like this:
#RequestMapping(value = "/content-files/upload/", method = RequestMethod.POST )
public #ResponseBody String handleFileUpload( #RequestParam("file") MultipartFile file) {
System.out.println("BrandController.uploadMultipart()");
String name=file.getName();
if (!file.isEmpty()) {
try {
byte[] bytes = file.getBytes();
BufferedOutputStream stream =
new BufferedOutputStream(new FileOutputStream(new File(name)));
stream.write(bytes);
stream.close();
return "You successfully uploaded " + name + "!";
} catch (Exception e) {
return "You failed to upload " + name + " => " + e.getMessage();
}
} else {
return "You failed to upload " + name + " because the file was empty.";
}
}
My html Page is :
<form enctype="multipart/form-data">
<input id="file-0a" class="file" type="file" file-model="myFile" name="myFile" />
<button ng-click="uploadFile()">upload me</button></form>
i have 2 jars in web-inf/lib:commons-upload.jar and commons-io.jar
I add this in my spring configuration file:
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="50000000"/>
</bean>
When I'm trying to upload a file, I get the error:
org.springframework.web.multipart.MultipartException: The current request is not a multipart request
When I'm trying to upload a file using MultipartHttpServletRequest in my spring function instead of Multipart i get this error:
java.lang.IllegalStateException: Current request is not of type [org.springframework.web.multipart.MultipartHttpServletRequest]: org.apache.catalina.connector.RequestFacade#196f5636
When i use HttpServletRequest request and i try to cast it i got a ClassCastException.
Nothing change when i cancel enctype="multipart/form-data" from my form Tag
Two things needed:
1. headers: {'Content-Type': 'application/x-www-form-urlencoded'}
2. The data passed should be converted to a URL-encoded string
reference:
enter link description here
I stuck into the same problem. Below is angular code
things you should do:
Remove the Content-Type from headers.
For multi file upload use below code
handleImageUpload = async (event) => {
if (event.target.files && event.target.files) {
const files = event.target.files;
_.map(files, (file) => {
//array for multiple files upload
this.imageData.push(file);
const reader = new FileReader();
//base64 encoded image for preview
reader.onload = async (event: any) => {
this.album.push(event.target.result);
};
reader.readAsDataURL(file);
});
this.uploadedImage = Promise.resolve(this.album);
}
}
In you submit handler use this code
const formData: any = new FormData();
// adding multiple files
this.imageData.map((i) => {
formData.append("files", i);
});
// add objects
_.map(body,(value,key) => {
formData.append(key, value);
});
// delete headers it will be set by browser
headers = headers.delete("Content-Type");
// make a call to api
this.httpClient
.post(url, formData, { headers })
.subscribe((res) => console.log(res));

Upload multipart form data with filename in Request Payload

I am still confused about different method of uploading files. The backend server is not under my control but I can upload a file using Swagger page or Postman. That means the server is functioning OK. But when I use AngularJS to do the upload, it doesn't work.
Here is what works using Postman to test. I am just using form-data:
Notice that Request Headers has Content-Type as multipart/form-data. But the Request Payload has filename and Content-Type as image/png.
Here is my code:
$http({
method: 'POST',
url: ApiUrlFull + 'Job/Item?smartTermId=0&name=aaa1&quantity=1&ApiKey=ABC',
headers: { 'Content-Type': undefined },
transformRequest: function(data) {
var fd = new FormData();
fd.append('file', params.imageData);
return fd;
}
})
params is just an object with file url in imageData.
My code also send similar URL params (so we can ignore that causing issues). But the Request Payload is base64 and it looks different as it is missing the filename field.
I have zero control of the backend and it is written in .NET.
So I guess my question is: Using Angular (either $http or $resource), how do I modify the request so that I am sending the correct Request Payload as how Postman does it? I cannot figure out how to reverse engineer this.
I have tried this https://github.com/danialfarid/ng-file-upload and it actually did OPTIONS request first before POST (assuming CORS issue). But the server gave 405 error for OPTIONS.
You can use something along the line of:
<input type="file" name="file" onchange="uploadFile(this.files)"/>
And in your code:
$scope.uploadFile = function(files) {
var fd = new FormData();
//Take the first selected file
fd.append("file", files[0]);
var uploadUrl = ApiUrlFull + 'Job/Item?smartTermId=0&name=aaa1&quantity=1&ApiKey=ABC';
$http.post(uploadUrl, fd, {
withCredentials: true,
headers: {'Content-Type': undefined },
transformRequest: angular.identity
}).success( ...all right!... ).error( ..damn!... );
};
My need was a follows.
In the form there is a default picture.
Clicking the picture opens a file select window.
When the user selects a file, it is uploaded right away to the server.
As soon as I get a response that the file is valid display the picture to the user instead of the default picture, and add a remove button next to it.
If the user clicks on an existing picture, the file select window reopens.
I tried to use a few code snippets on github that didn't solve the problem, but guided me in the right way, And what I ended up doing is as so:
Directive
angular.module("App").directive('fileModel', function ($parse) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
scope.files = {};
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
// I wanted it to upload on select of file, and display to the user.
element.bind('change', function () {
scope.$apply(function () {
modelSetter(scope, element[0].files[0]);
});
// The function in the controller that uploads the file.
scope.uploadFile();
});
}
};
});
Html
<div class="form-group form-md-line-input">
<!-- A remove button after file has been selected -->
<span class="icon-close pull-right"
ng-if="settings.profile_picture"
ng-click="settings.profile_picture = null"></span>
<!-- Show the picture on the scope or a default picture -->
<label for="file-pic">
<img ng-src="{{ settings.profile_picture || DefaultPic }}"
class="clickable" width="100%">
</label>
<!-- The actual form field for the file -->
<input id="file-pic" type="file" file-model="files.pic" style="display: none;" />
</div>
Controller
$scope.DefaultPic = '/default.png';
$scope.uploadFile = function (event) {
var filename = 'myPic';
var file = $scope.files.pic;
var uploadUrl = "/fileUpload";
file('upfile.php', file, filename).then(function (newfile) {
$scope.settings.profile_picture = newfile.Results;
$scope.files = {};
});
};
function file(q, file, fileName) {
var fd = new FormData();
fd.append('fileToUpload', file);
fd.append('fn', fileName);
fd.append('submit', 'ok');
return $http.post(serviceBase + q, fd, {
transformRequest: angular.identity,
headers: { 'Content-Type': undefined }
}).then(function (results) {
return results.data;
});
}
Hope it helps.
P.S. A lot of code was striped from this example, if you need clarification just comment.

AngularJS: how to implement a simple file upload with multipart form?

I want to do a simple multipart form post from AngularJS to a node.js server,
the form should contain a JSON object in one part and an image in the other part,
(I'm currently posting only the JSON object with $resource)
I figured I should start with input type="file", but then found out that AngularJS can't bind to that..
all the examples I can find are for wraping jQuery plugins for drag & drop. I want a simple upload of one file.
I'm new to AngularJS and don't feel comfortable at all with writing my own directives.
A real working solution with no other dependencies than angularjs (tested with v.1.0.6)
html
<input type="file" name="file" onchange="angular.element(this).scope().uploadFile(this.files)"/>
Angularjs (1.0.6) not support ng-model on "input-file" tags so you have to do it in a "native-way" that pass the all (eventually) selected files from the user.
controller
$scope.uploadFile = function(files) {
var fd = new FormData();
//Take the first selected file
fd.append("file", files[0]);
$http.post(uploadUrl, fd, {
withCredentials: true,
headers: {'Content-Type': undefined },
transformRequest: angular.identity
}).success( ...all right!... ).error( ..damn!... );
};
The cool part is the undefined content-type and the transformRequest: angular.identity that give at the $http the ability to choose the right "content-type" and manage the boundary needed when handling multipart data.
You can use the simple/lightweight ng-file-upload directive.
It supports drag&drop, file progress and file upload for non-HTML5 browsers with FileAPI flash shim
<div ng-controller="MyCtrl">
<input type="file" ngf-select="onFileSelect($files)" multiple>
</div>
JS:
//inject angular file upload directive.
angular.module('myApp', ['ngFileUpload']);
var MyCtrl = [ '$scope', 'Upload', function($scope, Upload) {
$scope.onFileSelect = function($files) {
Upload.upload({
url: 'my/upload/url',
file: $files,
}).progress(function(e) {
}).then(function(data, status, headers, config) {
// file is uploaded successfully
console.log(data);
});
}];
It is more efficient to send a file directly.
The base64 encoding of Content-Type: multipart/form-data adds an extra 33% overhead. If the server supports it, it is more efficient to send the files directly:
$scope.upload = function(url, file) {
var config = { headers: { 'Content-Type': undefined },
transformResponse: angular.identity
};
return $http.post(url, file, config);
};
When sending a POST with a File object, it is important to set 'Content-Type': undefined. The XHR send method will then detect the File object and automatically set the content type.
To send multiple files, see Doing Multiple $http.post Requests Directly from a FileList
I figured I should start with input type="file", but then found out that AngularJS can't bind to that..
The <input type=file> element does not by default work with the ng-model directive. It needs a custom directive:
Working Demo of "select-ng-files" Directive that Works with ng-model1
angular.module("app",[]);
angular.module("app").directive("selectNgFiles", function() {
return {
require: "ngModel",
link: function postLink(scope,elem,attrs,ngModel) {
elem.on("change", function(e) {
var files = elem[0].files;
ngModel.$setViewValue(files);
})
}
}
});
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app">
<h1>AngularJS Input `type=file` Demo</h1>
<input type="file" select-ng-files ng-model="fileArray" multiple>
<h2>Files</h2>
<div ng-repeat="file in fileArray">
{{file.name}}
</div>
</body>
$http.post with content type multipart/form-data
If one must send multipart/form-data:
<form role="form" enctype="multipart/form-data" name="myForm">
<input type="text" ng-model="fdata.UserName">
<input type="text" ng-model="fdata.FirstName">
<input type="file" select-ng-files ng-model="filesArray" multiple>
<button type="submit" ng-click="upload()">save</button>
</form>
$scope.upload = function() {
var fd = new FormData();
fd.append("data", angular.toJson($scope.fdata));
for (i=0; i<$scope.filesArray.length; i++) {
fd.append("file"+i, $scope.filesArray[i]);
};
var config = { headers: {'Content-Type': undefined},
transformRequest: angular.identity
}
return $http.post(url, fd, config);
};
When sending a POST with the FormData API, it is important to set 'Content-Type': undefined. The XHR send method will then detect the FormData object and automatically set the content type header to multipart/form-data with the proper boundary.
I just had this issue. So there are a few approaches. The first is that new browsers support the
var formData = new FormData();
Follow this link to a blog with info about how support is limited to modern browsers but otherwise it totally solves this issue.
Otherwise you can post the form to an iframe using the target attribute.
When you post the form be sure to set the target to an iframe with its display property set to none.
The target is the name of the iframe. (Just so you know.)
I hope this helps
You could upload via $resource by assigning data to params attribute of resource actions like so:
$scope.uploadFile = function(files) {
var fdata = new FormData();
fdata.append("file", files[0]);
$resource('api/post/:id', { id: "#id" }, {
postWithFile: {
method: "POST",
data: fdata,
transformRequest: angular.identity,
headers: { 'Content-Type': undefined }
}
}).postWithFile(fdata).$promise.then(function(response){
//successful
},function(error){
//error
});
};
I know this is a late entry but I have created a simple upload directive. Which you can get working in no time!
<input type="file" multiple ng-simple-upload web-api-url="/api/post"
callback-fn="myCallback" />
ng-simple-upload more on Github with an example using Web API.
I just wrote a simple directive (from existing one ofcourse) for a simple uploader in AngularJs.
(The exact jQuery uploader plugin is https://github.com/blueimp/jQuery-File-Upload)
A Simple Uploader using AngularJs (with CORS Implementation)
(Though the server side is for PHP, you can simple change it node also)

Resources