Angular Spring file upload - java

I'm trying to hit the Spring RestController and just getting:
o.s.web.servlet.PageNotFound : Request method 'POST' not supported
I believe something is missing to map the controller.
<div class="col-sm-1" style="background-color:#cccccc;" align="center"><span class="file-input btn btn-primary btn-file">Import file<input type="file" onchange="angular.element(this).scope().uploadScriptFile(this.files)"></input></span></div>
$scope.uploadCtrFile = function(files) {
console.log(">>>>>>>>>>>>>>>>uploadCtrFile");
var fd = new FormData();
//Take the first selected file
fd.append("file", files[0]);
console.log(">>>>>>>>>>>>>>>>uploadCtrFile angular.toJson: "
+ angular.toJson(fd, 2));
$http.post('/rest/uploadCtrFile/', fd,{
withCredentials: true,
headers: {'Content-Type': undefined },
transformRequest: angular.identity
}).success(function(fd, status, headers, config) {
$scope.success = ">>>>>>>>>>>>>>>>uploadCtrFile Success: "+JSON.stringify({data: fd});
console.log($scope.success);
})
.error(function(fd, status, headers, config) {
$scope.success = ( "failure message: " + JSON.stringify({data: fd}));
console.log($scope.success);
});
};
The controller looks like...
#RequestMapping(value = "/uploadCtrFile/", headers = "'Content-Type': 'multipart/form-data'", method = RequestMethod.POST)
#ResponseBody
public void uploadCtrFile(MultipartHttpServletRequest request, HttpServletResponse response) {
Iterator<String> itr=request.getFileNames();
MultipartFile file=request.getFile(itr.next());
String fileName=file.getOriginalFilename();
log.debug(">>>>>>>>>>>>>>>>>>>submitted uploadCtrFile: "+fileName);
}
The front end shows these messages...
">>>>>>>>>>>>>>>>uploadCtrFile angular.toJson: {}" tl1gen.js:607:0
"failure message: {"data": {"timestamp":1457380766467,"status":405,"error":"Method Not Allowed","exception":"org.springframework.web.HttpRequestMethodNotSupportedException","message":"Request method 'POST' not supported","path":"/rest/uploadCtrFile/"}}"
What am I missing ?

You send undefined as the value of Content-Type, here:
headers: {'Content-Type': undefined }
But your controller requires the Content-Type with multipart/form-data value:
#RequestMapping(..., headers = "'Content-Type': 'multipart/form-data'", ...)
You should either send the correct Content-Type header in your request, like:
headers: {'Content-Type': 'multipart/form-data'}
or remove the headers options from your controller definition:
#RequestMapping(value = "/uploadCtrFile/", method = RequestMethod.POST)

Related

Axios. Spring MVC returns a 415 response

I am using Vue.js, axios and Spring.
On the page I have the following axios code
axios({
method: 'post',
url: '/user/info',
params: {
'_csrf' : document.getElementById('csrf_id').value,
'name' : 'job',
'age' : '25',
},
headers: {'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json'}
});
And on the server I have a receiving method like this
#Controller
#RequestMapping("/user")
public class UserInfo {
#ResponseBody
#PostMapping(value = "/info", consumes = "application/x-www-form-urlencoded", produces = "application/json" + ";charset=utf8")
public String info(#RequestParam(value = "name") String name, #RequestParam(value = "age") String age) {
System.out.println(name);
System.out.println(age);
return "ok";
}
}
Axios makes a request to the server, but the server returns a 415 response.
The request headers are missing the application/x-www-form-urlencoded content type. I suspect the problem lies precisely in this.
Tell me, what am I doing wrong?
HttpMethod Post is a method of writing and transmitting data in the request body.
In your case, you put data through params. If you execute code as you write, data will be sent such as /user/info?_csrf=value&name=job&age=25 and there will be no data in the request body.
To get the response you want, you can modify it as below.
axios({
method: 'post',
url: '/user/info',
data: '_csrf=csrf&name=job&age=25',
headers: {'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json'}
});
change params keyword to data and write data like querystring.

JAVA: Upload Multipart file

I am struggling with Multipart file upload in Spring controller. I've read multiple questions, googles, but nothing seems to work.
I get
error: "Bad Request"
exception: "org.springframework.web.multipart.support.MissingServletRequestPartException"
message: "Required request part 'file' is not present"
My BE controller:
#RequestMapping(value = "/zip", method = RequestMethod.POST)
public void readFile(#RequestParam("file") MultipartFile file) throws IOException {
// code
}
FE, angularJS:
service.getZip = function getZip(file) {
var formData = new FormData();
formData.append('file', file);
return $http({
method: 'POST',
url: CONSTANTS.readFile,
data: formData,
headers: {'Content-Type': undefined}
}) .then(function (response) {
var data = response.data;
return data.id;
});
}
HTML:
<input type="file" id="file" name="file" accept=".txt"/>
also application.properties contain:
spring.http.multipart.enabled=false
UPDATE:
I no longer get that error when following #Byeon0gam advice to remove #RequestParam from my controller, but the my file is null as it comes to controller. Although in FE service, as I see, it's not empty:
change the Content-Type in your FE to:
headers: {'Content-Type': 'x-www-form-urlencoded'}
hope it will work for you.

Calling a RESTful service on an external domain via JQuery

I'm trying to calling a Java RESTful service by an html page, but I always get errors like the below:
No 'Access-Control-Allow-Origin' header is present on the requested resource", 405 (Method Not Allowed)
My simplest Java code is:
#SuppressWarnings({ "unchecked", "rawtypes" })
#RequestMapping(value = "/prenotazioni/{id}", method = RequestMethod.POST)
public ResponseEntity<Prenotazione> updatePrenotazione(HttpServletResponse response, #PathVariable int id, #RequestBody Prenotazione obj) {
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE");
response.addHeader("Access-Control-Allow-Headers", "Content-Type");
try {
prenotazioneService.updatePrenotazione(id, obj);
} catch (Exception e) {
return new ResponseEntity(e.getMessage(), HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<Prenotazione>(obj,HttpStatus.OK);
}
And the html code is:
$('#btnSalva').on('click', function(e){
//Creo la stringa JSON nel formato atteso dal servizio RESTful
var obj = '{"aula":{"id":' + $("#id_aula").val() + '},"id_utente":1,"data_inizio":"' + $("#datetimepicker1").data().DateTimePicker.date() + '","data_fine":"' + $("#datetimepicker2").data().DateTimePicker.date() + '"}';
var id = $("#id_evento").val();
var url = "http://localhost:8080/gestione_aule/prenotazioni/" + id;
//With $.post I've got error: No 'Access-Control-Allow-Origin
$.post( "http://localhost:8080/gestione_aule/prenotazioni/" + id, obj );
//With $.ajax I've got error: 405 (Method Not Allowed)
/*$.ajax({
url: "http://localhost:8080/gestione_aule/prenotazioni/" + id,
type: "POST",
crossDomain: true,
data: obj,
dataType: "jsonp",
success:function(result){
alert(JSON.stringify(result));
},
error:function(xhr,status,error){
alert(status);
}
});*/
/*$.postJSON = function(url, data, callback) {
return jQuery.ajax({
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
'type': 'get',
'url': url,
'data': JSON.stringify(data),
'dataType': 'jsonp',
'complete': function(e){
alert("c " + e);
},
'success': function(e){
alert("s " + e);
},
'error': function(e){
alert("e " + e);
}
});
};
$.postJSON(url, obj, function(e){alert(e);});*/
});
I've tried:
with and without specify response header in java servlet
mapping PUT and POST method
using $.post $.ajax
setting dataType json and jsonp
and many other combinations :)
But anyone worked for me... any suggest please?
Note: as I wrote in the code with $.post I've got error: No 'Access-Control-Allow-Origin, with ajax I've got error: 405 (Method Not Allowed)
Thans
The problem here that CORS (cross domain support) has 2 types of request:
Simple - such as HEAD, GET and POST. POST with content-type: application/x-www-form-urlencoded, multipart/form-data or text/plain
The rest requests are called Preflight requests
Your CORS request is a Preflight one. In Preflight requests the browser fires 2 requests:
OPTIONS - asking the server to verify that the origin, method and additional headers are trusted
The actual request - in your case POST
To fix the issue your case, add a new mapping that will handle the OPTIONS request:
#RequestMapping(value = "/prenotazioni/{id}", method = RequestMethod.OPTIONS)
public void updatePrenotazione(HttpServletResponse response, #PathVariable int id) {
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE");
response.addHeader("Access-Control-Allow-Headers", "accept, content-Type");
}

Spring MVC Ajax POST

I'm trying to post a JSON Object, with Ajax, to an Rest Spring MVC Controller, but I met some troubles.
Let's present you my code:
Controller
#RequestMapping(value = "/register/checkUsername.html", method = RequestMethod.POST, produces=MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody JsonResponse checkUsername(#RequestBody JsonUsername username) {
String usernameString = username.getUsername();
JsonResponse response = new JsonResponse();
response.setMessage(usernameString + "Available");
return response;
}
Ajax Function
function displayUsernamError(data) {
var json = "<h4>Eroare</h4><pre>"
+ JSON.stringify(data, null, 4) + "</pre>";
$('#usernameError').html(json);
}
function checkUsername(){
var username = document.getElementById("username");
var search = {
"username" : username.value
}
$.ajax({
type : "POST",
contentType : 'application/json; charset=utf-8',
dataType : 'json',
url : "http://localhost:8080/skill-assessment/register/checkUsername.html",
data : JSON.stringify(search),
success : function(result) {
console.log("SUCCESS: ", data);
displayUsernamError(result);
},
error: function(e){
console.log("ERROR: ", e);
displayUsernamError(e);
},
done : function(e) {
console.log("DONE");
}
});
}
And finally the html form:
<form:form modelAttribute="user" method="POST" enctype="utf8">
<tr>
<td><label>Username</label></td>
<td><form:input path="name" id="username" /></td>
<td>
<p id="usernameError">
</p>
</td>
</tr>
<button type="button" onClick="checkUsername()">Register</button>
</form:form>
So, I'm calling the checkUsername method when I press click on the Register button, only for test.
The ajax function is called and this send the JSON to the controller. I used the debug and the controller seems to get the JSON Object.
The problem is with the controller Response, because in the error div from my html page, I get this error:
HTTP Status 406
The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request \"accept\" headers.
Where is the problem? Who can give me an idea?
You need to specify the below code inside of the request mapping annotation
#RequestMapping(value = "/register/checkUsername.html", method = RequestMethod.POST, consumes=MediaType.APPLICATION_JSON_VALUE)
you no need to specify the produces attribute because #Responsebody will produce the content based on the request object content type[optional]. if you want other then it then only you have to mention it.
; charset=utf-8 is the default one in Ajax call. you no need mention it separately. try do these changes.
use #ResponseBody need object to json,
seems missing some jar file
(jackson-mapper-asl.jar and jackson-core-asl.jar)
try to import it
First check if your controller is returning a JSON. You can use any REST client and see what is the return header. If not then add the Jackson mapper bean.
Also, try setting the Accept header in the ajax call.
$.ajax({
headers: {
Accept : "application/json",
Content-Type: "application/json"
},
data: "data",
...
})
in .js(java script)
ajax function
var variable="test";
$.ajax({
url: baseUrl + "nameController/test1",
async: false,
data: {val: variable},
dataType: 'html',
success: function (dat) {
console.log(dat);
}
});
you create nameController.java
controller
#RequestMapping(value = "test1", method = RequestMethod.POST)
public #ResponseBody
String checkRoomStatusReservation(#RequestParam(value = "val", required = true) String parse) {
System.out.println("parse"+parse);
//value from parse=test
return parse;
}
you can try this

how to send empty value for MultipartFile

I'm using angularJs and spring 4.0,
My Controller code:
#RequestMapping(value = "/endpoint/add", method = RequestMethod.POST)
public #ResponseBody GenericFormResponse execute(
WebRequest wreq,
#RequestParam("epName") String epName,
#RequestParam("ipAddr") String ipAddr,
#RequestParam("useDefault") String useDefault,
#RequestParam("certFile") MultipartFile certFile) throws Exception {
.....................
}
my js(angualrJs) code:
var formData = new FormData();
formData.append("epName", $scope.epName);
formData.append("ipAddr", $scope.ipAddr);
formData.append("useDefault",$scope.defaultCert);
if(!$scope.defaultCert){
formData.append("certFile", upFile);
}
$http({
method: "POST",
url: "./service/endpoint/add",
data: formData,
transformRequest: angular.identity,
headers: {'Content-Type': undefined }
}).success(svcSuccessHandler)
.error(svcErrorHandler);
My problem is $scope.defaultCert=false the POST request is working fine, $scope.defaultCert = true i'm getting Bad request(400).
i tried below thing also,
if(!$scope.defaultCert){
formData.append("certFile", upFile);
}else{
formData.append("certFile", null);
}
How do i sent empty MultipartFile.
Thanks.
I created two services in controller, and two urls for both
#RequestMapping(value = "/endpoint/add-with-cert", method = RequestMethod.POST)
public #ResponseBody GenericFormResponse excecuteWithCert(
WebRequest wreq,
#RequestParam("epName") String epName,
#RequestParam("ipAddr") String ipAddr,
#RequestParam("useDefault") boolean useDefault,
#RequestParam("certFile") MultipartFile certFile) throws Exception {
LOGGER.debug("received request for endpoint creation with certificate");
GenericFormResponse response = new GenericFormResponse();
SessionManager sessionMgr = new SessionManager(wreq);
if(!sessionMgr.isLoggedIn()) {
response.setSuccess(false);
response.setGlobalErrorCode("not_logged_in");
return response;
}
...............
}
#RequestMapping(value = "/endpoint/add", method = RequestMethod.POST)
public #ResponseBody GenericFormResponse excecuteWithOutCert(
WebRequest wreq,
#RequestParam("epName") String epName,
#RequestParam("ipAddr") String ipAddr,
#RequestParam("useDefault") boolean useDefault) throws Exception {
LOGGER.debug("received request for endpoint creation without certificate");
...............
}
in js file:
var url = "./service/endpoint/add";
if(!$scope.defaultCert){
formData.append("certFile", upFile);
url = "./service/endpoint/add-with-cert";
}
$http({
method: "POST",
url: url,
data: formData,
transformRequest: angular.identity, headers: {'Content-Type': undefined }
}).success(svcSuccessHandler)
.error(svcErrorHandler);
I don't know is this correct approach or not, but it is fulfilled my requirement. working as i expect. Please suggest best answers.
You need to configure properly to enable multipart file upload in Spring 4.
Add the following line to application initializer class:
dispatcher.setMultipartConfig(
new MultipartConfigElement("/tmp", 25 * 1024 * 1024, 125 * 1024 * 1024, 1 * 1024 * 1024)
);
Here dispatcher is an instance of ServletRegistration.Dynamic
Refer this answer for more details.

Categories

Resources