Mapping same URL to different controllers in spring based on query parameter - spring

I'm using spring annotation based controller. I want my URL /user/messages to map to some controller a if query parameter tag is present otherwise to some different controller b. This is required because when parameter tag is present then some more parameters can be present along with that which i want to handle in different controller to keep the implementation clean.Is there any way to do this in spring. Also is there any other elegant solution to this problem ?

You can use the params attribute of the #RequestMapping annotation to select an controller method depending on Http parameters.
See this example:
#RequestMapping(params = "form", method = RequestMethod.GET)
public ModelAndView createForm() {
...
}
#RequestMapping(method = RequestMethod.GET)
public ModelAndView list() {
...
}
It is a REST style like Spring ROO uses: if the request contains the parameter forms then the createForm handler is used, if not the list method is used.

If you want to go the Spring route, you can checkout the HandlerInterceptor mentioned here. The Interceptor can take a look at your query param and redirect the link to something else that can be caught by another SimpleUrlMapper.
The other way is to send it to a single controller and let the controller forward to another action if the query parameter is "b".

Related

#ModelAttribute vs #RequestBody, #ResponseBody

#ModelAttribute
RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method =
RequestMethod.POST)
public String processSubmit(#ModelAttribute Pet pet) { }
http://.../?name=Something&age=100
public String doSomething(#ModelAttribute User user) { }
#RequestBody
#RequestMapping(value = "/user/savecontact", method = RequestMethod.POST
public String saveContact(#RequestBody Contact contact){ }
{ "name": "Something", "age": "100" } in request body
public String doSomething(#RequestBodyUser user) { }
#ModelAttribute will take a query string. so, all the data are being pass to the server through the url
#RequestBody, all the data will be pass to the server through a full JSON body
Now which one is the best approach ???
If both are for same purpose to bind to the bean..which one is the best practice or widely used as standard practice?
Both handles multi-part file and does it both have equivalent options with one another ?
https://javabeat.net/spring-multipart-file-upload/
How do i upload/stream large images using Spring 3.2 spring-mvc in a restful way
Does any one of them has lesser capabilities then the other one? Like length limitations, method limitations. Drawbacks
Which one is more secured in terms of security ?
As the javadoc suggests, it's the usage that sets them apart, i.e., use #ModelAttribute if you want to bind the object back to the web view, if this is not needed, use #RequestBody
#RequestBody
Usecases : Restful controllers (ex: produce and consume json/xml, processing direct document download requests, searching for stuff, ajax requests )
As the name suggests the if a method argument is annotated with #RequestBody annotation Spring converts the HTTP request body to the Java type of the method argument.
Is only allowed on method parameters (#Target(value={ PARAMETER}))
The body of the request is passed through an HttpMessageConverter to resolve the method argument depending on the content type of the request.
works for Post and not Get method.
#ModelAttribute
Usecases : web app controllers (ex: binding request query parameters, populating web views with options and defaults)
Uses data binders & ConversionService
Is allowed on methods and method params(#Target(value={METHOD, PARAMETER}))
Useful when dealing with model attributes for adding and retrieving model attributes to and from the Srping’s Model object
When used on METHODS, those methods are invoked before the controller methods annotated with #RequestMapping are invoked
binds a method PARAMETER or method return value to a named model attribute & the bound named model attributes are exposed to a web view
binds request query parameters to bean
For more information on Data Binding, and Type Conversion refer: https://docs.spring.io/spring/docs/5.1.x/spring-framework-reference/core.html#validation

how to apply post method to all request mappings in spring

How i can access to request POST data from different url-s to one controller method, for example I have /countries & /countries/{id} URL, It works very good with first one, because my code is
#RequestMapping(value = {"/{id}", "/{id}/"}, method = RequestMethod.GET)
public String getCountry(#PathVariable(value = "id", required = true) int id,ModelMap model) {
}
#RequestMapping(method = RequestMethod.POST)
public String deleteCountry(ModelMap model,HttpServletRequest request) {
}
And when I try to request POST data from second url I'm getting
HTTP Status 405 - Request method 'POST' not supported
Which is expectable because I haven't POST method with this mapping, but if I will be made one method for one mapping my code will be too ugly ant terrible, what solution I can use?
Hum why not add the "array" of value to your second method as well ?
#RequestMapping(value = {"", "/{id}"},method = RequestMethod.POST)
public String deleteCountry(ModelMap model,
HttpServletRequest request) {
Btw using POST verb to call an action that looks like it will delete the resource seems wrong, it should be a DELETE verb used
EDIT
But in reality, you should be creating 2 methods, as both those method are not supposed to do the same thing.
POST /countries should be creating country resources
POST /countries/{id} should be doing something else.
For an update prefer PUT /countries/{id}
And for a delete, prefer DELETE /countries/{id}
There is one way to have separate handler interceptors for different controllers.
Refer this link for details.
bind Spring HandlerInterceptor only to one controller
But I feel, it may be good you can create a common method to share business logic for this.
As Interceptor comes with proxy class for your controller which can be avoided unless you have complex logic.

REST API endpoint selection in Spring Boot

Given a controller like this:
#RestController
#RequestMapping("/cars") {
public class CarController{
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity<List<Cars>> getCars() { //logic }
#RequestMapping(method = RequestMethod.GET")
public ResponseEntity<List<Cars>> searchCar(#RequestParam("name") String name, #RequestParam("value") String value) { //logic}
}
If the url is like this localhost/cars I would like to access the getCars() method.
But if the url is :
localhost/cars?name=something&value=100 or
localhost/cars?name=something or
localhost/cars?value=100
I would like the second method to be accessed.
Is this possible to do?
You are still asking for the same list of resources, cars, only thing is that you are adding a filter or search / query criteria.
It would be beneficial to develop a query filter / criteria to support something like:
/cars?q=make+eq+acura (meaning make=acura)
/cars?q=price+lt+25000 (meaning price <25000)
and so on.
No it is not possible. because when a request comes to container then it will 1st scan all the URL and check uniqueness of the URL. If there is duplicate URL present then container will throws exception.
In your case you are using class level URL mapping, but you are not using method level URL mapping.
To access your getCars() method you need to use some URL like below
#RequestMapping(value = "/", method = RequestMethod.GET)
To access your 2nd method you need to use another mapping URL
#RequestMapping(values="/test", method = RequestMethod.GET")
You can't access
localhost/cars?name=something&value=100 or
localhost/cars?name=something or
localhost/cars?value=100
as you are using 2 parameters like #RequestParam("name") String name, #RequestParam("value") String value
you need to pass two parameter in your url like below
localhost/cars/test?name=something&value=100
if you don't want to pass any of two parameter then just pass it as null and check it inside your method

Spring Boot MVC request mapping overrides static resources

I want to have rest controller in Spring Boot to handle all requests like this: "/{arg}", EXCEPT "/sitemap.xml". How can I achieve that?
You could specify your request mapping on the controller level via regex and exclude some resources (e.g. 'excludeResourceA' and 'excludeResourceB') with:
#RestController
#RequestMapping(value = "/{arg:(?!sitemap.xml|excludeResourceA|excludeResourceB).*$}")
public class YourRestController {
// your implementation
}
Of course you can also specify the request mapping on the method level with the same regex relative to your controller path matching and you can pass the argument with #PathVariable("arg") String arg in your method signature to your method body if you need it.

Spring MVC Url Pattern Issue

I have an existing application ..where we have some jsp..in view folder of the
application Context.Now we need to migrate one of the JSP's to a spring mvc controller..
I was doing a sample application and this is what i observed...
if I have the pattern in web-xml as / and annotate the controller as
RequestMapping(value="/view/Track.jsp")
This doesnt work..but If I modify it as /view and
update it as
RequestMapping(value="Track.jsp") then it works..
What is the reason for this..and what should be the approach for the migration.
Spring MVC concatenates the mapping from the controller and the method. With your second mapping it results in: /view/Track.jsp - this is OK. When the mapping on th controller is /view/Track.jsp you probably don't have mapping on the method, right? That way spring don't know which method of the controller to call even if you got only one...
If you want to use only the mapping on the controller you can place #RequestMapping(method = RequestMethod.GET) on the method.
#Controller
#RequestMapping("/view/Track.jsp")
public class UserController {
#RequestMapping(method = RequestMethod.GET)
public String track( MapModel model ) {...}
}
Good practice is to use the mapping on the controller to "modulaize" your mappings if you got more controllers. That way you will prevent collision on the method mappings between controllers.

Resources