Values in braces in Spring Annotations - spring-mvc

This might be a simple question for those who know Spring, but since I am a newbie, I will ask it anyway.
I am going through some Spring code and I am not able to understand the following-
#RequestMapping(value="/{id}")
public void show(#PathVariable("id") long id, Model model) {...}
The comment for this section of the code is - "When using URI Templates, access parameters using the #PathVariable annotation.
Now earlier, I came across code like
#RequestMapping(value="/url/path")
public String list(Model model) {...}
By this, I understand that whenever the url "/url/path" is encountered, the list() method will be called, but I am not able to make sense of the former annotation. What does it mean?
Also, the next line says #PathVariable annotations can be limited via regular expressions
#RequestMapping(value="/{id}")
public void show(#PathVariable("id:[\\d]*") String idl) {...} // will match only numberic IDs
What does it mean?

16.3.2.2 URI Template Patterns
URI templates can be used for convenient access to selected parts of a URL in a #RequestMapping method.
For example, the URI Template http://www.example.com/users/{userId} contains the variable userId. Assigning the value fred to the variable yields http://www.example.com/users/fred.
In Spring MVC you can use the #PathVariable annotation on a method argument to bind it to the value of a URI template variable:
So, in your example:
#RequestMapping(value="/{id}")
public void show(#PathVariable("id") long id, Model model) {...}
This will extract the part of the URL represented by {id}, and bind it to the id method parameter, e.g. the path /42 will bind 42 to id.

Related

Spring mvc controller - how to do url restrictions

This is spring mvc controller /city/{cityName}
#RequestMapping(value = "/city/{cityName}")
public String getCity (#PathVariable("cityName") String cityName, Model uiModel) {
}
www.example.com/city/{cityName}
Here cityName is dynamically loaded from url, my website can't support some of cityName,
it supports only Bengaluru, Kochin, Hyderabad and Chennai, due to dynamic things
it supports other cities or whatever in the place of cityName, it gives error,
how to restrict cityName for only 4 cities mentioned above.
Is there any way in controller itself or we have to maintain table(hard coded hashtable)
Suggest which is the best way to do
If you just want to have the four cities hardcoded in your code, you can also specify them using regular expression in #RequestMapping.
#RequestMapping("/cities/{cityName:Bengaluru|Kochin|Hyderabad|Chennai}")
public String getCity(#PathVariable("cityName") String cityName) {
}
That way if you specify a city which does not match the allowed values your controller will automatically return HTTP 404.
Update: Fixed the sample, the regex should go in #RequestMapping, not #PathVariable, sorry for the mistake
You'll either need separate controller mappings or to look up the cityName somewhere. That doesn't have to be hard-coded; you could instead use a YAML or properties file to initialize a Set or look it up in a database.
We can do at controller level statically
#RequestMapping(value = "/city/{cityname:bengaluru|chennai|kochin|hyderabad}")
OR we can create tables, query and put it in hashtable at application start up time.

#RequestParam How to handle incorrectly framed URLs

I am having a method test like below and making a RESTful webservice call to fetch the data,
#RequestMapping(value ="/select", method = RequestMethod.GET)
#ResponseBody
public String test(
#RequestParam(value="begin", defaultValue="0",required=false) final String begin
)
{
//Some java code
}
**RESTful Webservice Call:**
http://localhost:8081/a/b/c/select?begin=1
Returning the data properly
http://localhost:8081/a/b/c/select?begin:1
Here in the url = has been replaced with : for negative testing.
Here Spring ignores the given value 1 and picks the default value 0 and returns the data accordingly without errors
Question:
But I want to capture the actual URL field with value which is begin:1, do some validation and display error message that the url is incorrect.
I understood that begin:1 is not considered as part of url by spring and hence picks the default value. Wondering is there a way in Spring to capture the wrongly framed url's.
Any pointers would be helpful. Many Thanks!

Manually doing what the ModelAttribute annotation does in Spring MVC

I have an action method on a Spring MVC controller that has an argument annotated with #ModelAttribute. However, I don't know at compile time what the type of this parameter will be - I know the abstract base type but not the derived type.
At runtime, I will be able to decide what class I am expecting and I will be able to get a new'd up instance of this class. However, I have no idea what code I should be calling to parse the request data in the same fashion that #ModelAttribute does.
I've looked around and it seems that if i can get a hold of a WebRequestDataBinder I can use that to populate my object, but for that I need a BinderFactory and this is where I kind of get lost.
Can anyone give me some pointers here - or tell me that I am looking at it the wrong way and need to do something else?
you can inject the model itself in your controllers method and access the attribute yourself.
#RequestMapping(...)
public void doStuff(ModelMap model) {
Object attr = model.get("nameOfAttribute");
// ...
}

Can Spring MVC's REST framework accept query strings rather than PathVariables?

In all the tutorials and articles I have read regarding Spring 3's RESTful additions to Spring MVC, I have only ever seen one way for the use to pass in query data, via a #PathVariable, like so:
#RequestMapping(value="/shops/{name}", method=RequestMethod.GET)
public #ResponseBody Shop getShopInJSON(#PathVariable String name) {
...
}
which would respond to something like http://www.example.com/myservlet/shops/{name}, which could evaluate to http://www.example.com/myservlet/shops/thebestshoparound.
My question is this: Is it possible to set up a RESTful interface that takes requests based on classic query strings, e.g. http://www.example.com/myservlet/shops?name=thebestshoparound, instead of PathVariables?
This seems like a really simple question, but I can't find it anywhere online.
Yes, use the annotation #RequestParam, here is an example:
public #ResponseBody Shop getShopInJSON(#PathVariable String name, #RequestParam(value="query", required=false) String query) {
// do stuff
}

How to create a simple ASP.NET MVC action method that accepts HTTP-POST data?

i wish to have a simple Action in my controller that accepts a few optional values and some integer values.
this is my route i wish to have:
HTTP.POST
/review/create
and this is the Action method i would like...
[AcceptVerbs(HttpVerbs.Post)]
public JsonResult Create(int userId,
int addressId,
byte baseScore,
byte reviewType,
string subject,
string description)
{ ... }
I'm under the uneducated impression that all of those arguments above will be populated by the forms collection values ... but it's not happening. Also, I have no idea how I would write a route, to handle those ... because those values are form post data....
here's my global.asax....
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// Api - Search methods.
routes.MapRoute(
"Search Methods",
"{controller}/{action}"
);
In fact, the action method is never called because it doesn't seem to find it :(
But, if create and action without any of those arguments, then it finds it ?????????
How would you write a route and action method to accept some require and some optional arguments, for the route /review/create ?
As far as i can see you may rewrite your controller action like this:
public ActionResult Create(int foo, int bar, byte blah, string name, int? xxx) {
// code here
}
The ModelBinder will then ensure that foo,bar and blah are set. Name and xxx may be null. I can't test it a the moment, but i think return type of the action should be ActionResult.
If you are POST'ing a form, just make sure that the elements in your form (textboxes, checkboxes, textarea, etc) have id's that match the parameters in your method. As an alternative you can pass a FormCollection to the method, and do myFormCollection["foo"] to get a string representation of the value (which can then be parsed to an int).
From my experience, you are missing a number of key elements and concepts with this question.
First and foremost, I don't believe you can execute a POST without a form. The form has to contain the controls from which you pull the values that get passed to the controller method. If the goal is to simply unit test your POST controller method, then just call the method directly in your test, which it appears that you're doing, based on one of your comments. If you involve the view, then you're doing integration testing, not unit testing. Regardless of the test type, the test will always fail because you are choosing not to build the form. Even if you manage to force the POST using Fiddler, Firebug or any other mechanism, you're still not testing the view, you're testing the HTTP protocol.
I highly recommend that you employ a web application testing tool, such as WatiN or Selenium, to test your web pages, rather than throw together a quick-and-dirty test that really doesn't test anything useful.
In your post request set content-type="application/json; charset=UTF-8" and pass the values for the method parameter in JSON format. This should make Asp.MVC not to look in FormCollection for those values.

Resources