PostMapping application/x-www-form-urlencoded;charset=UTF-8 NULL? - java

application/x-www-form-urlencoded content type work very well
but application/x-www-form-urlencoded;charset=UTF-8 not work. return null value;
I tried send the request value from postman.
set key = body, value = "1234" all types such as form-data, raw, x-www.form
#PostMapping(value = "/test")
public ModelAndView success(HttpServletRequest request, #RequestParam String body, Header header) throws Exception{
log.debug("encodeData="+ body);
return null;
}
if I send string value through body, null return.

Related

How to send multipart form data with json value in Spring Boot

Hi there, I want to send to postman a body with json and an image in formd-data...
I save the form-data image in a s3 bucket, the entity has as an string attribute that is the link of the image
Here my spring boot controller
#PostMapping(consumes = { "multipart/mixed", "multipart/form-data" }, produces = MediaType.APPLICATION_JSON_VALUE)
public CharacterResponse createCharacter(#Valid #RequestBody CharacterRequest characterRequest, #RequestParam(value = "file", required = false) MultipartFile file) {
CharacterDto characterDto = mapper.map(characterRequest, CharacterDto.class);
CharacterDto createdCharacter = characterService.createCharacter(characterDto, file);
return mapper.map(createdCharacter, CharacterResponse.class);
}
I have already tried with #RequestParam and #RequestPart for the MultiPartFile...
I get this error:
"Content type 'multipart/form-data;boundary=--------------------------340232294957024834187036;charset=UTF-8' not supported"
From my point of view you could try this:
in method attributes use #RequestPart with values. And also you should use the same structure in your client (for ex. in postman for each part you should explicitly set content-type, auto content-type works not perfect. For keys you should use values from #RequestPart, and in values just put your payload)
#PostMapping(consumes={ MediaType.MULTIPART_FORM_DATA_VALUE },
produces=MediaType.APPLICATION_JSON_VALUE)
public CharacterResponse createCharacter(
#Valid #RequestPart("body") CharacterRequest characterRequest,
#RequestPart(value="file", required=false) MultipartFile file)
{
//code
}
Just using #RequestParam for both parameter should do the job.
#PostMapping("/api/path")
public CharacterResponse createCharacter(#Valid #RequestParam CharacterRequest characterRequest, #RequestParam(required = false) MultipartFile file) {
CharacterDto characterDto = mapper.map(characterRequest, CharacterDto.class);
CharacterDto createdCharacter = characterService.createCharacter(characterDto, file);
return mapper.map(createdCharacter, CharacterResponse.class);
}

Why #RequestParam annotation bind the value from request body?

I have this request
#RequestMapping(value = "/test", method = RequestMethod.POST)
public void test(ModelMap modelMap, #RequestParam(value = "name") String name) {
modelMap.put("result",name);
}
When I call this request from Postman and pass the Name parameter in the request body and in the URL, the result is like this :
But if I remove the parameter from request body, the request is like this :
Why does #RequestParam annotation bind the value from the request body first? and if it doesn't exist in the body, it bind the value from URL parameters
Because it's how ServletRequest works. Behind the scene #RequestParam is using ServletRequest#getParameter. If you take a look at the java doc it clearly state that query parameter or form post data are used.
For HTTP servlets, parameters are contained in the query string or posted form data.
If there is a multiple value for instance same key in query and post data then it returns the first value in the array returned by getParameterValues.
Furthermore you are using multipart/form-data content type so spring handle it with DefaultMultipartHttpServletRequest where parameters found in the body are returned first:
#Override
public String[] getParameterValues(String name) {
String[] parameterValues = super.getParameterValues(name);
String[] mpValues = getMultipartParameters().get(name);
if (mpValues == null) {
return parameterValues;
}
if (parameterValues == null || getQueryString() == null) {
return mpValues;
}
else {
String[] result = new String[mpValues.length + parameterValues.length];
System.arraycopy(mpValues, 0, result, 0, mpValues.length);
System.arraycopy(parameterValues, 0, result, mpValues.length, parameterValues.length);
return result;
}
}

Not able to receive parameters using Postmapping in Rest Controller

My Ajax code looks like this
$.ajax({
type : 'post',
url : url,
async : false,
data: {'txToClose': '1234,5678','sno':'0195'},
contentType : "application/x-www-form-urlencoded; charset=utf-8",
dataType : "json",
success : function(result,status,xhr){
console.log(result);
}
});
The txToClose value 1234,5678 will be coming from a textbox as comma separated string. The user will type them as comma separated.
Im trying to receive them in controller as
#PostMapping("/txToClose")
public ResultDto txToClose(HttpServletRequest request, HttpServletResponse response) throws BBException
{
logger.info("Called txToClose controller");
ResultDto resultDto = new ResultDto();
String txToClose= request.getParameter("txToClose");
String sno= request.getParameter("sno");
logger.info("Transactions to close :"+txToClose+", Serial Num :"+sno);
}
Output is
Transactions to close :null, Serial Num :null
What am I missing here?
You're posting your data as request body, which of course using request.getParameter() will give you null. getParameter() was used to retrieve value from URL parameter.
I'm not quite experience with SpringMVC but try to change your method parameter into
public ResultDto txToClose(#RequestBody ResultDto resultDto ) throws BBException
{
logger.info("Called txToClose controller");
String txToClose= resultDto.getTxtToClose();
String sno= resultDto.getSno();
logger.info("Transactions to close :"+txToClose+", Serial Num :"+sno);
}
I assume your ResultDto is same as your JSON format.
remove the line
contentType : "text/plain; charset=utf-8",
or use default contentType
contentType : "application/x-www-form-urlencoded; charset=utf-8",
It should work.
I solved the issue by adding #RequestBody ObjectNode json in the signature.
public ResultDto txToClose(HttpServletRequest request, HttpServletResponse response,#RequestBody ObjectNode json) throws BBException
{
logger.info("Called txToClosecontroller");
ResultDto result = new ResultDto();
String txToClose= json.get("txToClose").asText();
}

Posting a file and JSON data to Spring rest service

I am building a Spring rest service for uploading a file. There is a form that consists of various field and one field for uploading a file. On submitting that form, I am sending a multipart form request i.e. Content-Type as multipart/form-data.
So I tried with below
#RequestMapping(value = "/companies", method = RequestMethod.POST)
public void createCompany(#RequestBody CompanyDTO companyDTO, #RequestParam(value = "image", required = false) MultipartFile image){
.................
But, the above didn't work. So for time being,i sent JSON data as String and forming Company Object from that String in rest service like
#RequestMapping(value = "/companies", method = RequestMethod.POST)
public void createCompany(#RequestParam("companyJson") String companyJson, #RequestParam(value = "image",required = false) MultipartFile image) throws JsonParseException, JsonMappingException, IOException{
CompanyDTO companyDTO = new ObjectMapper().readValue(companyJson, CompanyDTO.class);
.............................
Can't I send JSON data with #RequestBody without passing JSON as String?
Appending the values to the URL what u have been doing now using #RequestParam.
#RequestParam annotation will not work for complex JSON Objects , it is specifi for Integer or String .
If it is a Http POST method , use of #RequestBody will make the Spring to map the incoming request to the POJO what u have created (condition: if the POJO maps the incoming JSON)
create FormData() and append your json and file
if (form.validate()) {
var file = $scope.file;
var fd = new FormData();
fd.append('jsondata', $scope.jsonData);
fd.append('file', file);
MyService.submitFormWithFile('doc/store.html', fd, '', (response){
console.log(response)
});
}
//Service called in above
MyService.submitFormWithFile = function(url, data, config, callback) {
$http({
method : 'POST',
url : url,
headers : {
'Content-Type' : undefined
},
data : data,
transformRequest : function(data, headersGetterFunction) {
return data;
}
}).success(function(response, status, header, config) {
if (status === 200) {
callback(response);
} else {
console.log("error")
}
}).error(function(response, status, header, config) {
console.log(response);
});
};
// in your java part using ObjectMapper
//it is like string
fd.append('jsondata', JSON.stringify($scope.jsonData));
#Autowired
private ObjectMapper mapper;
#RequestMapping(value = "/companies", method = RequestMethod.POST)
public void createCompany(#RequestParam String jsondata,
#RequestParam(required = true) MultipartFile file){
CompanyDto companyDto=mapper.readValue(jsondata, CompanyDTO.class);
......
}
Use below code snippet:
#RequestMapping(value= "/path", method=RequestMethod.POST, produces=MediaType.APPLICATION_JSON_VALUE)
public ResponseObject methodName(MyData input, #RequestParam(required=false) MultipartFile file) {
// To Do
}

Optional Request Header in Spring Rest Service

I'm using Spring Restful web service & having request body with request header as shown below:
#RequestMapping(value = "/mykey", method = RequestMethod.POST, consumes="applicaton/json")
public ResponseEntity<String> getData(#RequestBody String body, #RequestHeader("Auth") String authorization) {
try {
....
} catch (Exception e) {
....
}
}
I want to pass one more optional request header called "X-MyHeader". How do I specify this optional request header in Spring rest service?
Also, how do I pass this same value in response header??
Thanks!
UPDATE: I just found that I can set required=false in request header, so one issue is resolved. Now, the only issue remaining is how do I set the header in the response??
Use required=false in your #RequestHeader:
#PostMapping("/mykey")
public ResponseEntity<String> getData(
#RequestBody String body,
#RequestHeader(value = "Auth", required = false) String authorization) {}
This question is answered here:
In Spring MVC, how can I set the mime type header when using #ResponseBody
Here is a code sample from: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-ann-httpentity
#RequestMapping("/something")
public ResponseEntity<String> handle(HttpEntity<byte[]> requestEntity) throws UnsupportedEncodingException {
String requestHeader = requestEntity.getHeaders().getFirst("MyRequestHeader");
byte[] requestBody = requestEntity.getBody();
// do something with request header and body
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("MyResponseHeader", "MyValue");
return new ResponseEntity<String>("Hello World", responseHeaders, HttpStatus.CREATED);
}

Categories

Resources