405 Error : multipart/form-data with Spring - java

I am trying to send a Json string along with multiple files into my Spring Controller, however it would always give me a 405 Method Not Allowed Error, what am I doing wrong?
Javascript Code:
var formdata = new FormData();
formdata.append('user', JSON.stringify(userData));
files.forEach(file=> {
formdata.append('files', file);
});
jQuery.ajax({
url: "user/submitForm",
type: "POST",
data: formdata,
enctype: 'multipart/form-data',
processData: false,
contentType: false,
success: function (data)
{
console.log("SUCCESS");
},
error: function (request, status, error) {
alert(status + " : " + JSON.stringify(request));
}
});
Controller in Spring:
#PostMapping(value= "/submitForm", consumes = {
MediaType.APPLICATION_JSON_VALUE,
MediaType.MULTIPART_FORM_DATA_VALUE })
public ResponseEntity<?> userRegistration( #RequestPart("user") String user,
#RequestPart("files") List<MultipartFile> files, BindingResult bindingResult) {
ObjectMapper obj = new ObjectMapper();
User newUser = new User();
newUser = obj.readValue(user, User.class);
System.out.println("User : \n"+ newUser.toString());
System.out.println("Files : \n"+ files.toString());
return null;
}

This was the solution that I found from Antonio112009's answer
SOLUTION
#PostMapping(value = "/submitForm")
public ResponseEntity<?> userRegistration(
#RequestParam("user") String user,
#RequestParam(value = "files", required = false) List<MultipartFile> files) {
ObjectMapper obj = new ObjectMapper();
User userObj = new User();
.
.
.
}

I use another solution, who works as expected and are a bit more flexible from my point of view.
Front-end part is in Typescript.
Front-end
var formData = new FormData();
options.files.forEach(function (file) {
formData.append(file.name, file);
});
formData.append("myParam", "coucou");
var xhr = new XMLHttpRequest();
xhr.open("POST", "/rest/upload");
xhr.onload = function () {
var data = JSON.parse(xhr.responseText);
options.callback("success", options.files.map(function (file) {
return {
file: file,
content: data[file.name]
};
}));
};
xhr.send(formData);
Back-end (Java Spring)
#RestController
#RequestMapping(value = "/rest")
public class UploadController {
#PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<Boolean> upload(MultipartHttpServletRequest request) {
// Get param
Object myParam = request.getParameter("myParam");
// Get iteretaor on all files
Iterator<String> iterator = request.getFileNames();
MultipartFile multipartFile = null;
while (iterator.hasNext()) {
multipartFile = request.getFile(iterator.next());
final String fileName = multipartFile.getOriginalFilename();
final String fileSize = String.valueOf(multipartFile.getSize());
// Add logic ....
}
}
return new ResponseEntity(true);
}

Related

Send a data through Ajax, and the background never receives it

The foreground sends an ID to the background through Ajax, but the background never receives it. I have been troubled by this problem for a whole day, and I really need your help.Here are my JS and Controller and error messages
$('.category-wrap').on('click', '.now .delete', function (e) {
var target = e.currentTarget;
var pc = target.dataset.id;
var pcId = {'pcId':pc};
$.confirm('sure?',function () {
$.ajax({
url: deleteUrl,
type: 'POST',
data: pcId,
contentType: 'application/json',
cache: false,
success: function (data) {
if (data.success) {
$.toast('successfully delete!');
getList();
} else {
$.toast('Delete failed!');
}
}
});
})
});
#RequestMapping(value = "/removeproductcategory", method = RequestMethod.POST)
#ResponseBody
public Map<String, Object> removeProductCategory(#RequestBody Integer pcId,
HttpServletRequest request)
{...}
image 1
image 2
you send a json request var pcId = {'pcId':pc}; and try to receive an Integer #RequestBody Integer pcId
try to define a Pojo like this
class RequestData {
public Integer pcId;
}
and modifiy controller method parameter
#RequestMapping(value = "/removeproductcategory", method = RequestMethod.POST, consumes = "application/json" )
#ResponseBody
public Map<String, Object> removeProductCategory(#RequestBody RequestData pcId,
HttpServletRequest request)

How to send Optional parameters from angular and catch them in Java Controller?

I'm trying to send "search" parameters to Spring Controller but keep getting the 400 bad request . I tried #RequestParam("personalNumber")String personalNumber but it still doesn't work, so now I'm trying to get the wrapper , can you suggest how to send wrapper info to Java controller ? (Wrapper has instances of other classes)
AngularJs
angular.extend($scope, {
obj:{
personalNumber:"",
firstName:"",
lastName:"",
dateFrom:"",
dateTo:""
},
loadCarLoan: urls.BASE_API + "user/getOnlineApplicationList",
carLoanList:[
],
});
$scope.getCarLoan = function () {
$(".loader").show();
console.log("In the angular");
$http.post($scope.loadCarLoan + $.param($scope.obj))
.success(function (response) {
console.log(response);
if(response.success){
$scope.carLoanList = response;
}
$(".loader").hide();
}).error(function () {
$(".loader").hide();
$scope.carLoanList = [];
})
};
$scope.filter = function () {
$scope.getCarLoan();
};
Java Controller :
#RequestMapping(value = "user/getOnlineApplicationList", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.POST)
public #ResponseBody String getOnlineApplicationList(HttpSession session,
#RequestBody OnlineApplicationListWrapper wrapper) {
System.out.println("In the Controller Java");
HashMap<String, Object> jsonMap = new HashMap<>();
Car car = wrapper.getCar();
Loan loan = wrapper.getLoan();
CustPaymentPlan cpp = wrapper.getCpp();
NaturalPerson np = wrapper.getPerson();
jsonMap.put("success", "true");
jsonMap.put("car", car);
jsonMap.put("loan", loan);
jsonMap.put("cpp", cpp);
jsonMap.put("np", np);
System.out.println(wrapper.getCar().toString());
System.out.println(wrapper.getLoan().toString());
System.out.println(wrapper.getCpp().toString());
System.out.println(wrapper.getPerson().toString());
System.out.println("========");
System.out.println(gson.toJson(jsonMap));
return gson.toJson(jsonMap);
}
You need to change:
#RequestParam("personalNumber") String personalNumber
To:
#RequestParam(value = "personalNumber", required = false) String personalNumber
The required = false indicates to spring that the parameter can be optional.
No need to create a wrapper

How to convert JSon Object to Java Object?

Can Anyone help me on this, i m trying to convert complex json object send through ajax into a object. so that i can use this object to pass into my model.
The JSP code is:
function callRemovefilter()
{
var jsonObjects = {
address1: "Address_1",
city: "City",
pin: "PIN"
};
var jsonObjects2 = {
locality:"Loc1",
shippingType:"Regular",
shippingCost:20
};
var cust= JSON.stringify(jsonObjects);
var sales=JSON.stringify(jsonObjects2);
jQuery.ajax({
url: "http://localhost:8080/OnlineStore/kmsg/grocery/SaveSalesOrder",
type: "GET",
data: {CustomerInfo:cust,SalesModel:sales},
dataType: "json",
beforeSend: function(x) {
if (x && x.overrideMimeType) {
x.overrideMimeType("application/j-son;charset=UTF-8");
}
},
success: function(result) {
//Write your code here
}
});
}
// The controller code is
#RequestMapping(value = "/SaveSalesOrder", method = RequestMethod.GET)
#ResponseStatus(value=HttpStatus.OK)
public #ResponseBody String SaveCustomerOrder(#RequestParam Map<String,String> requestParams) throws Exception
{
ObjectMapper objectMapper = new ObjectMapper();
SalesCommandObject salesCommandObject= new SalesCommandObject();
salesCommandObject = objectMapper.readValue(body, SalesCommandObject .class);
return "Success";
}
// Code of JSP to send object to controller
var salesCommandObject = {}; salesCommandObject.CustomerInfo =
{
"address1": "Address_1",
"city": "City",
"pin": "PIN"
};
salesCommandObject.SalesModel =
{
"locality":'Loc1',
"shippingType":'Regular',
"shippingCost":20
};
$.ajax
({
type: "POST",
dataType : 'json',
async : true,
url: "http://localhost:8080/OnlineStore/kmsg/grocery/SaveSalesOrder",
data : JSON.stringify(salesCommandObject),
}).done(function(data,type,xml)
{
console.log(data);
}).fail(function()
{
alert("Something Bad Happened, Service failed");
})
Send objects, not jsonstrigs. And in controller in your method SaveCustomerOrder get an object, not Map, like:
#RequestMapping(value = "/SaveSalesOrder", method = RequestMethod.GET)
#ResponseStatus(value=HttpStatus.OK)
public #ResponseBody String SaveCustomerOrder(#RequestParam CustomerInfo ci, #RequestParam SalesModel sm) throws Exception
{
//your logic here
return "Success";
}
And add getters and setters to appropriate classes(i.e CustomerInfo, SalesModel) like:
`public class SalesModel{
private String sale_id;//or whatever field or property you need
public String getSale_Id() {
return sale_id;
}
public void setSale_Id(String si) {
this.sale_id = si;
}
}`

AngularJS Formdata file array upload

I'm trying to upload (actually POST) numerous small files in one go along with some key, value pairs:
$scope.uploadFiles = function(files) {
if (files.length === 0) {
return;
}
var formData = new FormData();
formData.append('keyName1', 'keyValue1');
formData.append('keyName2', 'keyValue2');
formData.append('keyName3', 'keyValue3');
for (var i = 0; i < files.length; i++) {
formData.append('files[]', files[i]);
}
$http.post( '/myEndpoint', formData, {
headers: { 'Content-Type': undefined },
transformRequest: angular.identity
}).success(function (result) {
console.log('YAY');
}).error(function () {
console.log('NAY');
});
}
Here's the Java backend:
#RequestMapping(value = "/myEndpoint", method = RequestMethod.POST)
#ResponseBody
public void uploadFiles(
#RequestParam("files") List<MultipartFile> fileList,
#RequestParam("keyName1") String keyName1,
#RequestParam("keyName2") String keyName2,
#RequestParam("keyName3") String keyName3,
HttpServletResponse response, HttpSession session) throws Exception {
log.debug(fileList.size()); // Always logs zero
}
The endpoint is being hit but the filesList length is zero. I've also changed
List<MultipartFile> fileList to MultipartFile[] filesArray
but that didn't work wither.
Can anyone shed some light please?
Cheers,
Paul
This might be helpful to you.
Angular:
$scope.uploadFiles = function(files) {
if (files.length === 0) {
return;
}
var formData = new FormData();
formData.append('keyName1', 'keyValue1');
formData.append('keyName2', 'keyValue2');
formData.append('keyName3', 'keyValue3');
for (var i = 0; i < files.length; i++) {
formData.append('file'+i, files[i]);
}
$http.post( '/myEndpoint', formData, {
headers: { 'Content-Type': undefined },
transformRequest: angular.identity
}).success(function (result) {
console.log('YAY');
}).error(function () {
console.log('NAY');
});
}
On Spring/Java Side:
RequestMapping(value = "/myEndpoint", method = RequestMethod.POST)
public #ResponseBody Object uploadFiles(MultipartHttpServletRequest request, HttpServletResponse response) throws IOException {
//do stuff here...
final String keyName1= request.getParameter('keyName1');
//and so on......
Iterator<String> iterator = request.getFileNames();
MultipartFile multipartFile = null;
while (iterator.hasNext()) {
multipartFile = request.getFile(iterator.next());
//do something with the file.....
}
}
BTW, on you angular side, you can always end the file on one go or with multiple request. It's up to you how you want that implemented.
I used a library on GitHub to help me accomplish this task with my Java Glassfish Server.
https://github.com/nervgh/angular-file-upload
I only needed to upload a single file, and here is the Java Backend to receive that file. This framework does have support to upload multiple files to the server.
#POST
#Path("/Endpoint")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response whateverEndPoint(#FormDataParam("fileName") InputStream fileInputStream,
#FormDataParam("fileName") FormDataContentDisposition contentDispositionHeader,
#FormDataParam("additionalParameter") String additionalParameter) {
System.out.println(contentDispositionHeader.getFileName());
String output = "File Received on the server: ";
return Response.status(200).entity(output).build();
}
Here is my angular controller that uses the framework:
angular.module('AppThing').controller('DemoController',function($rootScope,$scope,FileUploader){
//creating the uploader with the correct url
$scope.uploader = new FileUploader({
url : 'Endpoint',
method : 'POST',
alias: 'fileName',
autoUpload:true
});
//runs right after we add a file to the queue
$scope.uploader.onAfterAddingFile = function(item){
};
//runs right before we upload an item to the server
$scope.uploader.onBeforeUploadItem = function(item){
console.log('This is just before the image upload');
item.formData.push({'additionalParameter': $rootScope.additionalParameter});
};
$scope.uploader.onSuccessItem = function(item, response, status, headers) {
};
});
Hope this helps

How to return a text file with Spring MVC?

#RequestMapping( method = RequestMethod.POST, value = DataController.RESOURCE_PATH + "/file", headers = "content-type=application/json" )
#ResponseBody
public void export( #RequestBody JSONObject json, HttpServletResponse response ) throws IOException
{
String myString = "Hello";
}
The string is generated inside the Controller.
What I want is to send back to the user a Window where he can save a file which contains the myString.
$.ajax({
type: "POST",
url: url,
data: JSON.stringify(createJSON()),
contentType: "application/json",
success: function(response)
{
console.log("Exported JSON: " + JSON.stringify(createJSON()));
console.log(response);
},
error: function()
{
console.log(arguments);
alert("Export process failed.");
}
});
It clearly doesn't work in this current state and I am stuck at the moment.
here is a sample:
#RequestMapping( method = RequestMethod.POST,
value = DataController.RESOURCE_PATH + "/file",
headers = "content-type=application/json" )
public void export( #RequestBody JSONObject json, HttpServletResponse response )
throws IOException {
String myString = "Hello";
response.setContentType("text/plain");
response.setHeader("Content-Disposition","attachment;filename=myFile.txt");
ServletOutputStream out = response.getOutputStream();
out.println(myString);
out.flush();
out.close();
}
PS: don't forget to put some random stuff in your url (as parameter for example) to ensure your browser does not cache the text file.
To return a file you need to use the MediaType.APPLICATION_OCTET_STREAM as the response type.
I recommend using filesaver.js.
Then your solution will look like:
var text = JSON.stringify(createJSON());
var blob = new Blob([text], {type: "text/plain; charset=utf-8"});
saveAs(blob, "myfile.txt");

Categories