Spring Rest Controller, Path Variables on an overriden method's arguement - java

I have a controller annotated with #RestController and it implements an interface:
public interface ContratEndpoint {
String ROOT = "/api/contrats";
String GET_CONTRAT = "";
String GET_CONTRAT_PER_PK = "/{idContrat}";
#RequestMapping(value = GET_CONTRAT)
Contrat getContrat(#RequestParam(value = "contratId")Long contratId);
#RequestMapping(value = GET_CONTRAT_PER_ID)
ExtContrat getContratById(#PathVariable("idContrat") Long idContrat);
}
The controller:
#RestController
#RequestMapping(value = ContratEndpoint.ROOT)
public class ContratController implements ContratEndpoint {
//Injecting Services....
#Resource
private Mapper mapper;
#Override
public Contrat getContrat(Long contratId) {
return mapper.map(contratService.get(contratId),Contrat.class);
}
#Override
public ExtContrat getContratById(#PathVariable("idContrat") Long idContrat){
Preconditions.checkArgument(idContrat !=null);
return mapper.map(contratService.get(idContrat),ExtContrat.class);
}
.The above Code works just fine.
. But For the first inherited method , I didn't have to annotate arguments with #RequestParam and it worked just fine.
As for the second method I tried at first :
#Override
public ExtContrat getContratById(Long idContrat){
Preconditions.checkArgument(idContrat !=null);
return mapper.map(contratService.get(idContrat),ExtContrat.class);
}
. I expected the same behaviour Like the first Method, But i was wrong and the code ended up firing an IllegalArgumentException because of the check in ligne Preconditions.checkArgument(idContrat!=null).
My question is what is so specific about #PathVariable that i've missed ?
Or is it just something is wrong with my approach?
Thanks.

There is difference between Request param and path variable,seee below post that you can confirm with your uri the cause for the exception :
#PathVariable is to obtain some placeholder from the uri (Spring call it an URI Template) — see Spring Reference Chapter 16.3.2.2 URI Template Patterns
#RequestParam is to obtain an parameter — see Spring Reference Chapter 16.3.3.3 Binding request parameters to method parameters with #RequestParam
Assume this Url http://localhost:8080/SomeApp/user/1234/invoices?date=12-05-2013 (to get the invoices for user 1234 for today)
#RequestMapping(value="/user/{userId}/invoices", method = RequestMethod.GET)
public List<Invoice> listUsersInvoices(
#PathVariable("userId") int user,
#RequestParam(value = "date", required = false) Date dateOrNull) {
...
}

Related

How to find the id of the source link in a Spring controller [duplicate]

What is the difference between #RequestParam and #PathVariable while handling special characters?
+ was accepted by #RequestParam as space.
In the case of #PathVariable, + was accepted as +.
#PathVariable is to obtain some placeholder from the URI (Spring call it an URI Template)
— see Spring Reference Chapter 16.3.2.2 URI Template Patterns
#RequestParam is to obtain a parameter from the URI as well — see Spring Reference Chapter 16.3.3.3 Binding request parameters to method parameters with #RequestParam
If the URL http://localhost:8080/MyApp/user/1234/invoices?date=12-05-2013 gets the invoices for user 1234 on December 5th, 2013, the controller method would look like:
#RequestMapping(value="/user/{userId}/invoices", method = RequestMethod.GET)
public List<Invoice> listUsersInvoices(
#PathVariable("userId") int user,
#RequestParam(value = "date", required = false) Date dateOrNull) {
...
}
Also, request parameters can be optional, and as of Spring 4.3.3 path variables can be optional as well. Beware though, this might change the URL path hierarchy and introduce request mapping conflicts. For example, would /user/invoices provide the invoices for user null or details about a user with ID "invoices"?
#RequestParam annotation used for accessing the query parameter values from the request. Look at the following request URL:
http://localhost:8080/springmvc/hello/101?param1=10&param2=20
In the above URL request, the values for param1 and param2 can be accessed as below:
public String getDetails(
#RequestParam(value="param1", required=true) String param1,
#RequestParam(value="param2", required=false) String param2){
...
}
The following are the list of parameters supported by the #RequestParam annotation:
defaultValue – This is the default value as a fallback mechanism if request is not having the value or it is empty.
name – Name of the parameter to bind
required – Whether the parameter is mandatory or not. If it is true, failing to send that parameter will fail.
value – This is an alias for the name attribute
#PathVariable
#PathVariable identifies the pattern that is used in the URI for the incoming request. Let’s look at the below request URL:
http://localhost:8080/springmvc/hello/101?param1=10&param2=20
The above URL request can be written in your Spring MVC as below:
#RequestMapping("/hello/{id}") public String getDetails(#PathVariable(value="id") String id,
#RequestParam(value="param1", required=true) String param1,
#RequestParam(value="param2", required=false) String param2){
.......
}
The #PathVariable annotation has only one attribute value for binding the request URI template. It is allowed to use the multiple #PathVariable annotation in the single method. But, ensure that no more than one method has the same pattern.
Also there is one more interesting annotation:
#MatrixVariable
http://localhost:8080/spring_3_2/matrixvars/stocks;BT.A=276.70,+10.40,+3.91;AZN=236.00,+103.00,+3.29;SBRY=375.50,+7.60,+2.07
And the Controller method for it
#RequestMapping(value = "/{stocks}", method = RequestMethod.GET)
public String showPortfolioValues(#MatrixVariable Map<String, List<String>> matrixVars, Model model) {
logger.info("Storing {} Values which are: {}", new Object[] { matrixVars.size(), matrixVars });
List<List<String>> outlist = map2List(matrixVars);
model.addAttribute("stocks", outlist);
return "stocks";
}
But you must enable:
<mvc:annotation-driven enableMatrixVariables="true" >
#RequestParam is use for query parameter(static values) like: http://localhost:8080/calculation/pow?base=2&ext=4
#PathVariable is use for dynamic values like : http://localhost:8080/calculation/sqrt/8
#RequestMapping(value="/pow", method=RequestMethod.GET)
public int pow(#RequestParam(value="base") int base1, #RequestParam(value="ext") int ext1){
int pow = (int) Math.pow(base1, ext1);
return pow;
}
#RequestMapping("/sqrt/{num}")
public double sqrt(#PathVariable(value="num") int num1){
double sqrtnum=Math.sqrt(num1);
return sqrtnum;
}
1) #RequestParam is used to extract query parameters
http://localhost:3000/api/group/test?id=4
#GetMapping("/group/test")
public ResponseEntity<?> test(#RequestParam Long id) {
System.out.println("This is test");
return ResponseEntity.ok().body(id);
}
while #PathVariable is used to extract data right from the URI:
http://localhost:3000/api/group/test/4
#GetMapping("/group/test/{id}")
public ResponseEntity<?> test(#PathVariable Long id) {
System.out.println("This is test");
return ResponseEntity.ok().body(id);
}
2) #RequestParam is more useful on a traditional web application where data is mostly passed in the query parameters while #PathVariable is more suitable for RESTful web services where URL contains values.
3) #RequestParam annotation can specify default values if a query parameter is not present or empty by using a defaultValue attribute, provided the required attribute is false:
#RestController
#RequestMapping("/home")
public class IndexController {
#RequestMapping(value = "/name")
String getName(#RequestParam(value = "person", defaultValue = "John") String personName) {
return "Required element of request param";
}
}
it may be that the application/x-www-form-urlencoded midia type convert space to +, and the reciever will decode the data by converting the + to space.check the url for more info.http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1
#PathVariable - must be placed in the endpoint uri and access the query parameter value from the request
#RequestParam - must be passed as method parameter (optional based on the required property)
http://localhost:8080/employee/call/7865467
#RequestMapping(value=“/call/{callId}", method = RequestMethod.GET)
public List<Calls> getAgentCallById(
#PathVariable(“callId") int callId,
#RequestParam(value = “status", required = false) String callStatus) {
}
http://localhost:8080/app/call/7865467?status=Cancelled
#RequestMapping(value=“/call/{callId}", method = RequestMethod.GET)
public List<Calls> getAgentCallById(
#PathVariable(“callId") int callId,
#RequestParam(value = “status", required = true) String callStatus) {
}
Both the annotations behave exactly in same manner.
Only 2 special characters '!' and '#' are accepted by the annotations #PathVariable and #RequestParam.
To check and confirm the behavior I have created a spring boot application that contains only 1 controller.
#RestController
public class Controller
{
#GetMapping("/pvar/{pdata}")
public #ResponseBody String testPathVariable(#PathVariable(name="pdata") String pathdata)
{
return pathdata;
}
#GetMapping("/rpvar")
public #ResponseBody String testRequestParam(#RequestParam("param") String paramdata)
{
return paramdata;
}
}
Hitting following Requests I got the same response:
localhost:7000/pvar/!##$%^&*()_+-=[]{}|;':",./<>?
localhost:7000/rpvar?param=!##$%^&*()_+-=[]{}|;':",./<>?
!# was received as response in both the requests
#RequestParam:We can say it is query param like a key value pair
#PathVariable:-It is came from URI

Spring RequestMapping conflicts

I have a RequestMapping that displays a grid, and another one for loading objects in grid.
#RequestMapping(value = "/grid/{objType}", method = RequestMethod.GET)
public String displayGrid(Model model, #PathVariable("objType") String objType) {
// some code here
}
#RequestMapping(value = "/loadGrid", method = RequestMethod.GET)
public #ResponseBody String loadGrid(Model model) {
// returns a JSON
}
When i display the grid the url is like ../grid/User
The problem is that after the grid is created and a request loadGrid is made, the request is mapped to /grid/loadGrid which is resolved by the first method instead of the second one.
Is there any way to make a request for /grid with nothing after it ?
Or any way to resolve this conflict ?
The collision isn't a problem; spring resolves exact matches first. (see the source code of AbstractHandlerMethodMapping)
Your problem is that you've incorrectly defined your mappings. If you define a #RequestMapping at the class level, all the method #RequestMappings will be prefixed with the defined value.
The following maps three endpoints: /grid, /grid/{objType} and /grid/loadGrid. Note that the #RequestMapping for get() defines no value, only its method because it inherits from the class-level annotation.
#Controller
#RequestMapping(value = "/grid")
public class GridController {
#RequestMapping(method = RequestMethod.GET)
public String get(Model model) {
// ...
}
#RequestMapping(value = "/{objType}", method = RequestMethod.GET)
public String displayGrid(Model model, #PathVariable("objType") String objType) {
// ...
}
#ResponseBody
#RequestMapping(value = "/loadGrid", method = RequestMethod.GET)
public String loadGrid(Model model) {
// ...
}
}

How use PUT method in Springboot Restcontroller?

Am developing an application using Spring boot.I tried with all representations verbs like GET, POST , DELETE all are working fine too. By using PUT method, it's not supporting in spring boot. Whether I need to add any new configuration.
Put method works only the request not have any parameters. If i add any query parameter or form data it doesnt work. Kindly any expertize will help me to solve this issue.
#RequestMapping("/student/info")
#RequestMapping(method = RequestMethod.PUT)
public #ResponseBody String updateStudent(#RequestParam(value = "stdName")String stdName){
LOG.info(stdName);
return "ok";
}
Request method 'PUT' not supported
This code will work fine. You must specify request mapping in class level or in function
level.
#RequestMapping(value = "/student/info", method = RequestMethod.PUT)
public #ResponseBody String updateStudent(#RequestBody Student student){
LOG.info(student.toString());
return "ok";
}
Have you tried the following Request Mapping:
#RequestMapping(value = "/student/info", method = RequestMethod.PUT)
There's no need to separate the value and the Request Method for the URI.
Since Spring 4.3 you can use #PutMapping("url") : https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/PutMapping.html
In this case it will be:
#PutMapping("/student/info")
public #ResponseBody String updateStudent(#RequestParam(value = "stdName")String stdName){
LOG.info(stdName);
return "ok";
}
I meet the same issue with spring boot 1.5.*,I fixed it by follow:
#RequestMapping(value = "/nick", method = RequestMethod.PUT)
public Result updateNick(String nick) {
return resultOk();
}
Add this bean
#Bean
public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
return new TomcatEmbeddedServletContainerFactory(){
#Override
protected void customizeConnector(Connector connector) {
super.customizeConnector(connector);
connector.setParseBodyMethods("POST,PUT,DELETE");
}
};
}
see also
https://stackoverflow.com/a/25383378/4639921
https://stackoverflow.com/a/47300174/4639921
you can add #RestController annotation before your class.
#RestController
#RequestMapping(value = "/v1/range")
public class RangeRestController {
}

Spring MVC: Get Unnamed Request Parameter

What is the simplest way to access an unnamed request parameter in a Spring MVC controller? Is there an annotation for this similar to #RequestParam?
HTTP Delete request with unnamed parameter:
http://localhost/myEndPoint?someUnnamedParam
Controller:
public class MyController {
#RequestMapping(value = {"/myEndPoint"}, method = RequestMethod.DELETE)
public void deleteThing() {
// Do something with unnamed param
}
}
Details: Spring 3.0.7
I think you misunderstand.
In /myEndPoint?someUnnamedParam, you have a parameter named someUnnamedParam with a String value of "", ie. an empty String. It's parsed as an equivalent to /myEndPoint?someUnnamedParam=.
You can get a set of parameter names and use those as values.
#RequestMapping(value = {"/myEndPoint"}, method = RequestMethod.DELETE)
public void deleteThing((#RequestParam Map<String, List<String>> params) {
Set<String> paramNames = params.keySet();
...
}
You can always use
#RequestMapping(value = {"/myEndPoint"}, method = RequestMethod.DELETE)
public void deleteThing(HttpServletRequest request) {
String param = request.getQueryString();
// Do something with request
}
and perform any operations you need on request

How to read flash attributes after redirection in Spring MVC 3.1?

I would like to know how to read a flash attributes after redirection in Spring MVC 3.1.
I have the following code:
#Controller
#RequestMapping("/foo")
public class FooController {
#RequestMapping(value = "/bar", method = RequestMethod.GET)
public ModelAndView handleGet(...) {
// I want to see my flash attributes here!
}
#RequestMapping(value = "/bar", method = RequestMethod.POST)
public ModelAndView handlePost(RedirectAttributes redirectAttrs) {
redirectAttrs.addFlashAttributes("some", "thing");
return new ModelAndView().setViewName("redirect:/foo/bar");
}
}
What I am missing?
Use Model, it should have flash attributes prepopulated:
#RequestMapping(value = "/bar", method = RequestMethod.GET)
public ModelAndView handleGet(Model model) {
String some = (String) model.asMap().get("some");
// do the job
}
or, alternatively, you can use RequestContextUtils#getInputFlashMap:
#RequestMapping(value = "/bar", method = RequestMethod.GET)
public ModelAndView handleGet(HttpServletRequest request) {
Map<String, ?> inputFlashMap = RequestContextUtils.getInputFlashMap(request);
if (inputFlashMap != null) {
String some = (String) inputFlashMap.get("some");
// do the job
}
}
P.S. You can do return return new ModelAndView("redirect:/foo/bar"); in handlePost.
EDIT:
JavaDoc says:
A RedirectAttributes model is empty when the method is called and is
never used unless the method returns a redirect view name or a
RedirectView.
It doesn't mention ModelAndView, so maybe change handlePost to return "redirect:/foo/bar" string or RedirectView:
#RequestMapping(value = "/bar", method = RequestMethod.POST)
public RedirectView handlePost(RedirectAttributes redirectAttrs) {
redirectAttrs.addFlashAttributes("some", "thing");
return new RedirectView("/foo/bar", true);
}
I use RedirectAttributes in my code with RedirectView and model.asMap() method and it works OK.
Try this:
#Controller
public class FooController
{
#RequestMapping(value = "/foo")
public String handleFoo(RedirectAttributes redirectAttrs)
{
redirectAttrs.addFlashAttribute("some", "thing");
return "redirect:/bar";
}
#RequestMapping(value = "/bar")
public void handleBar(#ModelAttribute("some") String some)
{
System.out.println("some=" + some);
}
}
works in Spring MVC 3.2.2
For all those like me who were having problems with seeing the POST url in the browser when a validation would fail.
The POST url is a private url that should not be exposed to users but it was automatically rendered when a validation failed. i.e. if a field was below a minimum length. I was using #Valid. I wanted the original GET url of the form to show at all times even when validation bounced back to the form, so I did the following:
if (validation.hasErrors()) {
redirectAttributes.addFlashAttribute("org.springframework.validation.BindingResult.story", validation);
redirectAttributes.addFlashAttribute("story", story);
return new ModelAndView("redirect:/january/2015");
where story is the form object representation, redirectAttributes are RedirectAttributes you put in the method signature and validation is the BindingResult. /january/2015 is the mapping to the GET controller where the form lives.
After this implementation, in the mapping for /january/2015, story comes in intact as follows:
Story story= (Story) model.asMap().get("story");
//story from the POST method
I had to augment my GET method and check if this was not null. If not null, then send this to the form else I would send a newly initialized Story type to the form as default behaviour before.
In this manner, I am able to return to the form with the bindingresults intact (errors show on form) but have my GET url in place of the post url.

Categories

Resources