I am new to Spring and I want to write a controller which will take Collection/Iterable as arguments. Like this:
#RequestMapping(value = "friends", method = RequestMethod.POST)
public #ResponseBody Callable<Iterable<User>>
getFriendsOfUser(#RequestParam(required = true, name = "mobiles") Iterable<String> mobs) {
// return callable
}
There is no compilation error, but I cannot make it work. Can you say how will this work? And how shall be the request to this api be constructed?
public String getFriendsOfUser(#RequestParam(required = true, value = "mobiles") String[] mobiless){
....
}
and your mobile should be
mobiles=myValue1&mobiles=myValue2&mobiles=myValue3
or
mobiles=myvalue1,myValue2,myValue3
still if you have any doubt post your front-end code and Ajax call.
You've mapped a POST method so you might need #RequestBody instead of #RequestParam
#RequestParam is, as the name implies, for request parameters: [host]/endpoint?param=foo&secondParam=bar
whereas
#RequestBody is for JSON/XML or any other type content sent as the request's body.
Related
Is there a way to get information about HTTP request from the method down the callstack of the Spring request handler method?
In other words given I have a handler method like:
#GetMapping("/hello")
public String hello(#RequestParam(value = "name", defaultValue = "World") String name) {
MyInternalClass.doSomeAction();
return String.format("Hello %s!", name);
}
I am looking for means to get the information about HTTP request (such as URL, headers, etc.) within the code of the doSomeAction() static method in the MyInternalClass class.
The constraint is that I cannot modify the original method (hello()).
You can add a Request parameter of type HttpServletRequest
#GetMapping("/hello")
public String hello(
#RequestParam(value = "name", defaultValue = "World") String name,
HttpServletRequest originalRequest) {
// HERE: call another method here
return String.format("Hello %s!", name);
}
Have a look at the Spring Reference Documentation, Chapter "Method Arguments"
Part 2
However, I was looking for a method that does not force developers to change their code. I will try to add an example to my question, so it will be more verbose.
You can use the RequestContextHolder to get the request attributes.
HttpServletRequest request =
((ServletRequestAttributes)RequestContextHolder.getRequestAttributes())
.getRequest();
RequestContextHolder.getRequestAttributes() is a static method, that can be invoked from every where (even for a class that is no Spring Bean). But it is required that it is invoked from a thread that was triggert by a HTTP request.
Using spring MVC I receive multipart files in the controller this way
#RestController
public class FilesController {
#PostMapping(path = ("/files"), consumes = {"multipart/form-data", "multipart/mixed"})
public Reference createFile(
#RequestPart(value = "description") FileDescription fileDesc,
#RequestPart(value = "attachments", required = false) List<MultipartFile> attachments) {
Some parts of the multipart request may contain headers like "Content-ID", "Content-Location" and so on. But spring interface MultipartFile doesn't provide a method to get any header I want, only getContentType as I see. How I can get all provided headers?
Important point is that in request I could have multipart/mixed as a part of multipart/form-data. So every part of the message has its own map of headers. If I use #RequestHeader, I can see main headers of the request, but there are no headers of a specific part of multipart.
There might be another way, but the one I know of is to ask for a MultipartHttpServletRequest in your method signature.
#PostMapping(path = ("/files"), consumes = {"multipart/form-data", "multipart/mixed"})
public Reference createFile(MultipartHttpServletRequest multipartRequest)
You can ask for other arguments if need be.
This object allows you to access details of the multipart in a finer-grained way. For example, you can access each part's header using getMultipartHeaders(String paramOrFileName). You also have methods to access the files content this way, so you would not typically need to keep you #RequestPart inside the method signature.
We can also use javax.servlet.http.Part instead of MultipartFile. Interface Part has getHeader method.
#RequestPart(value = "attachments", required = false) List<Part> attachments
You can get all request headers by using this
#RequestHeader Map<String,String> headers After that, you can search for the header you are looking for.
You can use #RequestHeader annotation to retrieve all the headers from the request, like this:
#RestController
public class FilesController {
#PostMapping(path = ("/files"), consumes = {"multipart/form-data", "multipart/mixed"})
public Reference createFile(
#RequestHeader Map<String, String> headersMap
) {
// Use headersMap here
}
or if you want a single header's value, then you can specify the name of the header in #RequestHeader annotation, like this:
#RestController
public class FilesController {
#PostMapping(path = ("/files"), consumes = {"multipart/form-data", "multipart/mixed"})
public Reference createFile(
#RequestHeader("Content-ID") String contentId,
#RequestHeader("Content-Location") String contentLocation,
) {
// Use contentId, contentLocation here
}
I'm trying to write a simple HTTP REST service using Spring 4.
I'm having troubles sending data to a POST endpoint
#RequestMapping(value = "/onlyPost", produces = "application/json", method
= RequestMethod.POST)
public #ResponseBody ResponseEntity<?> createUser(#RequestParam("value1")
String param1, #RequestParam("value2") String param2) {
....
}
While trying to send data with Postman, I receive a 400 message (obviously the values are setted in the request's body)
"message": "Required String parameter 'value1' is not present",
What I have noticed is that the issue is somewhat related to the headers, because when I remove the postman's header (Content-Type: application/json) everything works fine.
I tried for more than one hour fixing this by myself with no results. Any hints?
#RequestParam is used to read a URL query parameter.
http://localhost:8080/springmvc/onlyPost?value1=foo&value2=bar
For instance, in the URL above, value1 and value2 are query parameters that you can read using that annotation.
But if you want to read a JSON request instead, you need to change the method to:
#RequestMapping(value = "/onlyPost", method = RequestMethod.POST,
consumes = "application/json")
public #ResponseBody ResponseEntity<?> createUser(#RequestBody User user) {
....
}
where User is a POJO holding the two fields:
public class User {
private String value1;
private String value2;
// getters and setters...
}
HTTP 400 is returned when your request is badly formatted, i.e. missing required request parameters
#RequestParam is for URL Params, if you want to pass them like that, you call
<api_url>/onlyPost?value1=<value1>&value2=<value2>
but... if you want to create user you should rather use #RequestBody and put your user data there. Something like that:
#RequestMapping(value = "/users", produces = "application/json", method
= RequestMethod.POST)
public #ResponseBody ResponseEntity<?> createUser(#RequestBody User user) {
[...]
}
if you are creating REST api you should use concrete endpoints, here is a pretty cool reading with some tips: http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api
I want to create a REST service with spring that takes a bunch of parameters. I'd like these parameters to be mapped automatically into a complex transfer object, like:
#RequestMapping(method = RequestMethod.GET)
#ResponseBody
public String content(#RequestParam RestDTO restDTO) {
Sysout(restDTO); //always null
}
public class RestDTO {
private boolean param;
//getter+setter
}
But: when I execute a query like localhost:8080/myapp?param=true the restDTO param remains null.
What am I missing?
Try with localhost:8080/myapp?param=true.
Probably a case where another pair of eyes sees the obvious :)
EDIT
Remove #RequestParam from method signature, works for me.
It turned out I have to omit the #RequestParam for complex objects:
#RequestMapping(method = RequestMethod.GET)
#ResponseBody
public String content(RestDTO restDTO) {
Sysout(restDTO);
}
So, I see few problems (if it's not mistyping of course):
localhost:8080/myapp¶m=true "&" isn't correct, you have to use "?" to split params from URL like localhost:8080/myapp?param=true.
I don't see mapping value in #RequestMapping(method = RequestMethod.GET) (But if you caught the request you've made correct configuration).
I have mapped one of my method in one Controller to return JSON object by #ResponseBody.
#RequestMapping("/{module}/get/{docId}")
public #ResponseBody Map<String, ? extends Object> get(#PathVariable String module,
#PathVariable String docId) {
Criteria criteria = new Criteria("_id", docId);
return genericDAO.getUniqueEntity(module, true, criteria);
}
However, it redirects me to the JSTLView instead. Say, if the {module} is product and {docId} is 2, then in the console I found:
DispatcherServlet with name 'xxx' processing POST request for [/xxx/product/get/2]
Rendering view [org.springframework.web.servlet.view.JstlView: name 'product/get/2'; URL [/WEB-INF/views/jsp/product/get/2.jsp]] in DispatcherServlet with name 'xxx'
How can that be happened? In the same Controller, I have another method similar to this but it's running fine:
#RequestMapping("/{module}/list")
public #ResponseBody Map<String, ? extends Object> list(#PathVariable String module,
#RequestParam MultiValueMap<String, String> params,
#RequestParam(value = "page", required = false) Integer pageNumber,
#RequestParam(value = "rows", required = false) Integer recordPerPage) {
...
return genericDAO.list(module, criterias, orders, pageNumber, recordPerPage);
}
Above do returns correctly providing me a list of objects I required.
Anyone to help me solve the mystery?
If a controller method returns null, Spring interprets that as saying that you want the framework to render the "default view".
It would be better, I think, that when the method is #RequestBody-annotated, this logic should not apply, but perhaps that's hard to implement - how would it handle a null return from a method that normally returns XML, for example?
Anyway, to stop this from happening, you need to make sure you return something, like an empty Map.