Does anyone know why I am getting the above error? I cant see why? please see my code below and advise where i can fix this error. The aim is to upload multiple files to a location. It used to work for a single file, however it looks like the formdata or ajax request is only used to accepting one file and not multiple. I am not doing this in PHP, only javascript/java. Please help.
function makeProgress(number){
var url = getRelativeURL("web/fileUpload");
var formData = new FormData();
formData.append('number', number);
fls = document.getElementById("attachmentFileUploadInput").files; //length of files...
console.log(fls);
for(j=0;j<fls.length;j++){
formData.append('files[]', fls[j]); //note files[] not files
}
//formData.append('file', $('input[type=file]')[0].files[0]);
console.log("form data " + formData);
$.ajax({
url : url,
data : formData,
processData : false,
contentType : false,
type : 'POST',
success : function(data) {
FileUploadVisible(true);
$('#attachmentModal').modal('hide')
$(':input','#attachmentModal').val("");
$("#pbarmain").hide();
$("#pbar").hide();
$("#actionPlanDiv").hide();
setObjectEnabled('#Upload',false);
},
error : function(err) {
FileUploadErrorVisible(true);
}
});
}
#Bean(name = "multipartResolver")
public CommonsMultipartResolver commonsMultipartResolver(){
CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
commonsMultipartResolver.setDefaultEncoding("utf-8");
commonsMultipartResolver.setMaxUploadSize(5000000); // 5000000 -> 5MB
return commonsMultipartResolver;
}
}
#RequestMapping(value = { "/fileUpload" }, method = RequestMethod.POST)
#ResponseBody
public String uploadFile( #RequestParam("number") String number, #RequestParam("files") MultipartFile[] files, MultipartHttpServletRequest req, HttpServletResponse res)
{
for (MultipartFile file : files) {
try {
File directory = new File(UPLOADED_FOLDER + number);
if (! directory.exists()){
directory.mkdir();
}
byte[] bytes = file.getBytes();
Path path = Paths.get(UPLOADED_FOLDER + number + "//" + file.getOriginalFilename());
Files.write(path, bytes);
logger.info("You have successfully uploaded '" + file.getOriginalFilename() + "'");
return("File Uploaded");
} catch (Exception e) {
res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
logger.error("Failed to upload file '" + file.getOriginalFilename() + "'", e);
return("File Not Uploaded");
}
}
return "redirect:/fileUpload";
}
}
you have to use..
#RequestMapping(method = RequestMethod.POST, headers = ("content-
type=multipart/*"), produces = "application/json", consumes = "file/*")
public String uploadFile(#RequestParam("number") String number, #RequestParam("files") MultipartFile files) {
and also use contentType: 'multipart/form-data into javascript code
url : url,
data : formData,
processData : false,
contentType: 'multipart/form-data',
type : 'POST',
success : function(data) {
Related
I'm trying to send two lists of JSON, a DateTime, int, string, and file to a C# controller via JQuery AJAX POST request.
All data sends fine except the two object arrays, they send nothing.
I've tried changing them from a list of objects to a list of strings to convert from there, but the array is received as one long string, making it nonconvertible via JsonConvert in Newtonsoft.Json.
I've tried logging the formdata objects in order to check their validity, and they seem fine in console. I'm not entirely sure where I've messed up.
Here is my JS:
var formData = new FormData();
formData.append("assignedUsers", JSON.stringify(assignedUsers));
formData.append("ccUsers", JSON.stringify(ccUsers));
formData.append("dueDate", $("#DueDate").val());
formData.append("goalClassID", parseInt(goalClassID));
formData.append("goalDescription", $("#GoalDescription").val());
formData.append("file", document.getElementById("GoalFile").files[0]);
for (var pair of formData.entries()) {
console.log(pair[0] + ', ' + pair[1]);
}
$.ajax({
url: api + "main/CreateGoal",
type: "POST",
data: formData,
cache: false,
dataType: "json",
processData: false,
contentType: false,
success: function (result) {
if (result) {
toastr.success("Goal successfully created");
} else {
toastr.error("Goal creation failed.");
}
}
})
This is my C# Controller:
public bool CreateGoal([FromForm]List<User>AssignedUsers, [FromForm]List<User>CCUsers, [FromForm]DateTime DueDate, [FromForm]int GoalClassID, [FromForm]string GoalDescription, [FromForm]IFormFile File = null)
This is User class
public class User : Base
{
public string UUID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public int Permission { get; set; }
public string FullName { get { return FirstName + " " + LastName; } }
}
Both object arrays are empty because you are posting them as json, but all the data is posted as form-data and [FromForm] expects input to be form-data of special format. Everything is working fine for primitive values because they added to FormData like this
formData.append(key, value)
as expected. But when you need to pass an array of objects it must be of the following format
formData.append("obj[0].Field1", field1Val)
formData.append("obj[0].Field2", field2Val)
formData.append("obj[0].Field3", field3Val)
...
formData.append("obj[1].Field1", field1Val)
formData.append("obj[1].Field2", field2Val)
formData.append("obj[1].Field3", field3Val)
So you need to update your code to something like this
var formData = new FormData();
formData.append("assignedUsers[0].uuid", assignedUsers[0].uuid);
formData.append("assignedUsers[0].firstName", assignedUsers[0].firstName);
...
formData.append("assignedUsers[1].uuid", assignedUsers[1].uuid);
formData.append("assignedUsers[1].firstName", assignedUsers[1].firstName);
...
formData.append("dueDate", $("#DueDate").val());
formData.append("goalClassID", parseInt(goalClassID));
formData.append("goalDescription", $("#GoalDescription").val());
formData.append("file", document.getElementById("GoalFile").files[0]);
Well, since this is not very good way to write code you would like to create a function doing it for you. The final solution is
function addUsers(formdata, users, name) {
for (var i = 0; i < users.length; i++) {
addSingleUser(formdata, users[i], name + "[" + i + "]");
}
}
function addSingleUser(formdata, user, name) {
for (var key in user) {
formdata.append(name + "." + key, user[key]);
}
}
var formData = new FormData();
formData.append("dueDate", $("#DueDate").val());
formData.append("goalClassID", parseInt(goalClassID));
formData.append("goalDescription", $("#GoalDescription").val());
formData.append("file", document.getElementById("GoalFile").files[0]);
addUsers(formData, assignedUsers, "assignedUsers")
addUsers(formData, ccUsers, "ccUsers")
$.ajax({
url: "/Home/CreateGoal",
type: "POST",
data: formData,
cache: false,
dataType: "json",
processData: false,
contentType: false,
success: function (result) {
if (result) {
toastr.success("Goal successfully created");
} else {
toastr.error("Goal creation failed.");
}
}
})
So due to the way the ajax call needs to handle files it does not also process the models in the array as json objects. So, I made a change where the first method will return the created object and the second method will then accept the file.
C# Controller
[HttpPost("CreateGoal")]
public Goal CreateGoal(List<User> AssignedUsers, List<User>CCUsers, DateTime DueDate, int GoalClassID, string GoalDescription)
{
try
{
//Code to save new goal model
return goal;
}
catch (Exception e)
{
return null;
}
}
[HttpPost("CreateGoalFile")]
public bool CreateGoalFile([FromForm] int GoalID, [FromForm]IFormFile File)
{
try
{
//Code to save file and make database relation
return true;
}
catch (Exception)
{
return false;
}
}
Javascript solution
$.post(api + "main/CreateGoal",
{ AssignedUsers: assignedUsers, CCUsers: ccUsers, DueDate: $("#DueDate").val(), GoalClassID: parseInt(goalClassID), GoalDescription: $("#GoalDescription").val() },
function (result) {
if (document.getElementById("GoalFile").files[0] != null) {
var formData = new FormData();
formData.append("goalID", result.id);
formData.append("file", document.getElementById("GoalFile").files[0]);
$.ajax({
url: api + "main/CreateGoalFile",
type: "POST",
data: formData,
cache: false,
dataType: "json",
processData: false,
contentType: false,
success: function (result) {
if (result) {
toastr.success("File uploaded sucessfully created");
} else {
toastr.error("File uploaded failed.");
}
}
})
}
toastr.success("Goal successfully created");
}
)
i saw this code for downloading a file into client from server...
public ActionResult Download()
{
string file = #"c:\someFolder\foo.xlsx";
string contentType = "application/pdf";
return File(file, controntType, Path.GetFileName(file));
}
But the problem is that i have to do two different things in this Download method.Atfirst ,i want to download the file and then i need to get path of downloaded file and pass in to a documentviewr to display it.so i wrote this code in view razor.
function navigate(target) {
$.ajax({
url: '#Url.Action("Download", "Patient")',
type: 'GET',
dataType: 'json',
cache: false,
data: { 'filepath' : target },
success: function (results) {
event.preventDefault();
documentViewr.loadDocument(results);
},
error: function () {
alert('Error occured');
}
});
}
and in my controller i wrote this:
[HttpGet]
public JsonResult Download(string filepath)
{
var content_type = "";
//path = Path.Combine("D:\file1", filename);
content_type = "application/pdf";
FilePathResult file = File(filepath, content_type,
Path.GetFileName(filepath));
String sDocID, sDocPath;
ViewerController vc = new ViewerController();
sDocPath = Server.MapPath(".") + "\\App_Data\\sample.docx";
sDocID = vc.LoadDocument(sDocPath);
return Json(sDocID, JsonRequestBehavior.AllowGet);
}
so my question is that how i can merge this two actions together?because if i do not return FilePathResult i can not download the file..my another question is that how i can define the path in which file will be downloded?can i tell it to download files into for example Server.MapPath(".") + "\App_Data\...??
i will be grateful if u can help me....
I want to write a common method in angular js for downloadin few types of file like jpg/txt/word/pptx/xls/xlsx...
I am able to write the java code for same and set the content type in header based on the file type. But i am unable to get the header value in angular js controller on successfull return. Any help will be appreciated. Following is the code snippet. I want to get the filename and content type in my angular controller in success method.
#RequestMapping(value = "/vceSearch/downloadCCD", method = RequestMethod.POST)
public ResponseEntity<byte[]> downloadCCDTemplate(#RequestParam String ccdNumber,
HttpServletRequest request, HttpServletResponse response) {
String methodName = "downloadCCDTemplate(#RequestParam String ccdNumber," + "HttpServletRequest request)";
log.info("Entry : " + methodName);
try {
CCDDownloadBean reponseData = null;
reponseData = vceService.downloadCCDTemplate(ccdNumber);
//response.setContentType(reponseData.getContentType());
//response.setHeader("Content-Disposition", "attachment; filename=" + reponseData.getFilename());
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType(
reponseData.getContentType()));
String filename = reponseData.getFilename();
headers.setContentDispositionFormData(filename, filename);
log.info("Exit : " + methodName);
return new ResponseEntity<byte[]>(reponseData.getCont(), HttpStatus.OK);
} catch (C2PCException E) {
log.error("Exception :", E);
return new ResponseEntity<byte[]>(HttpStatus.SERVICE_UNAVAILABLE);
}
}
Angular Js Contoller -
$scope.downloadCCD = function(ccd) {
//ccd = "9590-00003-CCD";
ccd="1560-00381-CCD"
FactoryVFListData.downloadCCD(ccd).success(
function(response,request,headers) {
alert(response.data);
saveAs(new Blob([ response ], { type : "image/jpeg" }), "Amar.jpg");
});
}
Angular Js Sevice :-
downloadCCD : function(ccdNumber) {
promise = $http({
url : 'vce/vceSearch/downloadCCD?ccdNumber='+ ccdNumber,
method : "POST",
data: '',
headers: {'Content-type': 'application/json'},
responseType: 'arraybuffer'
});
return promise;
},
I am quite new to JQuery and I was trying to do some asynchronous multipart form uploading. The form consist of few data fields and a file type. I have set up the server side code (Spring) like this:
#RequestMapping(method = RequestMethod.POST)
public #ResponseBody
Upload multipleSave(MultipartHttpServletRequest request)
{
Upload upload = new Upload();
Iterator<String> iterator = request.getFileNames();
while (iterator.hasNext())
{
MultipartFile file = request.getFile(iterator.next());
try
{
System.out.println(MessageFormat.format("File Length: {0}", Arrays.toString(file.getBytes())));
System.out.println("File Type: " + file.getContentType());
upload.setContent(file.getBytes());
upload.setDocId(id++);
upload.setError(null);
upload.setName(file.getName());
upload.setSize(file.getSize());
fileList.put(upload.getDocId().toString(), upload);
} catch (Exception e)
{
System.out.println("Error occurred: " + e);
upload.setError("500: Something went wrong!");
}
}
return upload;
}
and client side code like this:
function processFileUpload()
{
console.log("fileupload clicked");
var formData = new FormData();
formData.append("file", files[0]);
$.ajax({dataType: 'json',
url: "/SpringJqueryFileUpload/upload",
data: formData,
type: "POST",
enctype: 'multipart/form-data',
processData: false,
contentType: false,
success: function (result) {
alert('success' + JSON.stringify(result));
},
error: function (result) {
alert('error' + JSON.stringify(result));
}
});
}
When I do submit, the server responds with this:
java.lang.IllegalArgumentException: No converter found for return value of type: class com.upload.model.Upload
I am wondering with error. Could I be missing something here??
I would try changing your annotation to:
#RequestMapping(method = RequestMethod.POST, produces=MediaType.APPLICATION_JSON_VALUE)
And make sure you have Jackson (which Spring uses for JSON serialization) properly on your path. Also, make sure your Upload class is serializable, e.g. is not private or anything like that. If it is just a normal Java bean type class it should be fine.
Lastly, if that doesn't work you can turn on Spring debug logs with something like:
log4j.category.org.springframework.web=ALL
in your log4j.properties file.
As the title states, I'm trying to send data from a Javascript frontend to my C# MVC 5 backend, and it doesn't seem to make it. I've run through it with the debugger in Visual Studio and the data I'm trying to pass always ends up null.
Here is my front end code:
var file = $("#my-file").files[0];
file = file[0];
var formData = new FormData();
var MyData = {
Name: "Form 133",
Attachments: {
Type: "Check"
}
};
formData.append('file', file);
$.ajax({
type: "POST",
url: '/NMISProduct/Index',
contentType: false,
processData: false,
data: { formData: formData, MyData: MyData },
success: function (result) {
console.log(result);
},
error: function (xhr, status, p3, p4) {
var err = "Error " + " " + status + " " + p3 + " " + p4;
if (xhr.responseText && xhr.responseText[0] == "{")
err = JSON.parse(xhr.responseText).Message;
console.log(err);
}
});
Backend code:
[HttpPost]
public async Task<JsonResult> Index(MyData MyData)
{
Debug.WriteLine(Request.Params["MyData"]);
Debug.WriteLine(MyData.Name);
try
{
foreach (string file in Request.Files)
{
var fileContent = Request.Files[file];
if (fileContent != null && fileContent.ContentLength > 0)
{
// get a stream
var stream = fileContent.InputStream;
// and optionally write the file to disk
var fileName = fileContent.FileName;
var path = Path.Combine(Server.MapPath("~/App_Data/"), fileName);
using (var fileStream = System.IO.File.Create(path))
{
stream.CopyTo(fileStream);
}
}
}
}
catch (Exception)
{
return Json("Upload failed");
}
return Json("File uploaded successfully");
}
public class MyData
{
public string Name { get; set; }
public Attachment Attachments { get; set; }
}
public class Attachment
{
public string Type { get; set; }
}
As I stated, on the Backend MyData always ends up being null. What am I doing wrong?
jQuery docs state:
processData (default: true)
Type: Boolean
By default, data passed in to the data option as an object (technically, anything other than a string) will be processed and transformed into a query string, fitting to the default content-type "application/x-www-form-urlencoded". If you want to send a DOMDocument, or other non-processed data, set this option to false.
The problem is that you are trying to send MyData as an object while setting processData to false. Which will result in the data not being processed before being send. The data property should contain a query string of the form key1=value1&key2=value2, or an object of the form {key1: 'value1', key2: 'value2'}, the latter will be converted into a query string before being send unless you are setting processData to false.
So if you want to send your formData along with the MyData you will need to append the MyData to the formData before sending it like so.
formData.append('Name', 'Form 133');
formData.append('Type', 'Check');
And then in the $ajax call add the FormData to the data property like so.
data: formData,
contentType setting to false you just told him to not sending any data in the header so basically the tag [HttpPost] become useless.
processData setting to false you told him not to process has and object so rendering MyData useless again by setting to true if i remember correctly it mean process anything beside string has a object.
$.ajax({
url: "#Url.Action("Your METHOD", "Your Controller")",
type: "POST",
contentType: "application/json",
data: JSON.stringify({ MyData: MyData}),
success: function(response) {
response ? alert("Process") : alert("Boom");
}
});