Spring RequestMapping conflicts - java

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) {
// ...
}
}

Related

Using a String variable in RequestMapping value

I have the following:
#Value("${apiVersion")
private String apiVersion;
#RequestMapping(value = "/{apiVersion}/service/call", method = RequestMethod.POST)
And I expected the URL to be:
/apiVersion/service/call
But it turns out {foo} accept any value, it doesn't actually use the String.
Is there a way for me to use the String value as part of the URL?
EDIT
The issue is that I have multiple calls that us that value.
#RequestMapping(value = apiVersion + "/call1", method = RequestMethod.POST)
#RequestMapping(value = apiVersion + "/call2", method = RequestMethod.POST)
#RequestMapping(value = apiVersion + "/call3", method = RequestMethod.POST)
etc.
Technically I can declare constants for each one like you suggested, but it doesn't sound optimal. If there is no way to do it then it is fine, I was just wondering if there is.
SOLUTION
Adding general mapping to the controller.
#RequestMapping("${apiVersion}")
If you want to apply it for all methods in a controller declare it on the controller class level:
#RestController
#RequestMapping("/test")
public class MyController { ...
and you do not need to prepend it before method path.
Otherwise it should be constant so like:
private static final String FOO = "test";
and prepend it before method path like:
FOO + "/service/call"
If you just want to predefine the path in Java just do
#RequestMapping(value = foo + "/service/call", method = RequestMethod.POST)
PathVariables in SpringMvc are meant to be a placeholder for endpoints like in the following
#GetMapping(value = "/books/{id}")
public String displayBook(#PathVariable id) { ... }

pass JSON to jsp from Spring controller. How represent JSON?

I need to represent JSON in table. I get JSON from my controller and i don`t know what next...How can i pass JSON to exact jsp or i should not do it?Sorry, I m new in JSON.
And what should i do after method add(...)? What should i return.
Here is my controller code
#Controller
public class MainController {
#Autowired
private ClientLogManager clientLogManager;
#ResponseBody
#RequestMapping(value = "/api/getlog/{appId}", method = RequestMethod.GET)
public List<ClientLog> getAll(#PathVariable Integer appId, Model model) {
List clientLogs = clientLogManager.get(appId);
return clientLogs;
}
#ResponseBody
#RequestMapping(value = "/api/log", method = RequestMethod.POST)
public ClientLog add(#RequestBody ClientLog clientLog) {
clientLogManager.add(clientLog);
return clientLog;
}
}
u can get your json data via a simple html file ...
in your jsp file you can get this list with jQuery
$.getJSON('localhost:8080/api/getlog/12', function (clientlogs) {
for(clientlog : clientlogs){
console.log(clientlog.id);
}
});
if u have a save operation you had better use PUT method
#ResponseBody
#RequestMapping(value = "/api/log", method = RequestMethod.PUT)
public ClientLog add(#RequestBody ClientLog clientLog) {
clientLogManager.add(clientLog);
return clientLog;
}

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

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) {
...
}

Cannot handle request by requestMapping

I need to handle requests like
www.example.com/student/thisisname?age=23&country=UK&city=London
I am just interested in thisisname part and value of city parameter.
I have following RequestMapping but it does not work. I tried {name}{.*:city} as well.
#RequestMapping(value = "/{name:.*}{city}", method = RequestMethod.GET)
You can do it by 2 ways. Either using #RequestParam or #PathVariable
By Using #RequestParam
#RequestMapping(value = "/name", method = RequestMethod.GET)
public void someMethod(#RequestParam String city){}
By using #PathVariable
#RequestMapping(value = "/name/{city}", method = RequestMethod.GET)
public void someMethod(#PathVariable String city){}
You can use any of this method just you need to concentrate on URL
You can handle it using PathVariable and RequestParam annotation. In below code name is thisisname part and city is query param city value.
#RequestMapping(value = "/student/{name}", method = RequestMethod.GET)
public void someMethod(#PathVariable String name, #RequestParam("city") String city){
}

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