I am new to Spring MVC, while going through the various tutorial online got this doubt, I encountered several syntax of writing the function under #requestMapping annotation
For eg.
Syntax 1:
'''
#RequestMapping(method = RequestMethod.GET)
public String printHello(ModelMap model) {
model.addAttribute("message", "Hello Spring MVC Framework!");
return "hello";
}
'''
Syntax 2:
'''
#RequestMapping(value = "/welcome",method = RequestMethod.GET)
public ModelAndView printer()
{
ModelAndView m = new ModelAndView("hello");
m.addObject("Welcome", "Success !! Krishna");
return m;
}
'''
Syntax 3:
'''
#RequestMapping(value = "/welcome",method = RequestMethod.GET)
public ModelAndView printer(HttpServletRequest request , HttpServletResponse response)
{
//Some code
}
'''
My question is :
How Tomcat knows which parameters my function is expecting and how does it provide the requested parameter to my function
Tomcat only provides the actual instance of HttpServletRequest and HttpServletResponse (i.e. Those object defined in the Servlet API) .The actual work that decide and resolve the argument values is done by spring-mvc. It then calls the controller method with the resolved values.
It basically boils down to using Reflection API to get the type information of the parameter of the matched controller method (e.g its annotation setting , data type etc). Based on these type information, it resolves the values based on the rules define in the docs . After all values are resolved , it uses Reflection API again to invoke this controller method with the resolved value.
Pseudo codes looks likes:
FooController controller = context.getBean(FooController.class);
Method matchedControllerMethod = findMatchedControllerMethod(controller, httpServletRequest);
int parameterCount = matchedControllerMethod.getParameterCount().
Object[] resolvedParamValues = new Object[parameterCount];
for (int i = 0; i < parameterCount; i++) {
Parameter param = matchedControllerMethod.getParameters(i);
if(param.getType().equals(ModelMap.class)){
resolvedParamValues[i] = Util.getModelMap();
}else if(param.getType().equals(HttpServletRequest.class)){
resolvedParamValues[i] = httpServletRequest;
}else if(param.getType().equals(HttpServletResponse.class)){
resolvedParamValues[i] = httpServletResponse
}else if{
.......
........
}
}
matchedControllerMethod.invoke(controller ,resolvedParamValues);
In reality , the codes are much more fancy than that. For example, it uses strategy pattern to replace those if-else check with an abstraction called HandlerMethodArgumentResolver. In other words , by looking at all the implementations of HandlerMethodArgumentResolver ,you can know how it resolves the arguments for all possible cases.
It has less to do with requestMapping and more to do with requestParam which would be responsible for deciphering the type of parameters.
Read more:
https://dzone.com/articles/using-the-spring-requestmapping-annotation
Related
I think the fault comes from ulr introduced in the RedirectView parameter, but I tried different URL's and I can't make it work.
This is my project estructure:
And this is the get method from Spring MVC in controller package
#GetMapping("/planetForm")
#ResponseBody
public RedirectView toPlanetForm(Model model, #RequestParam(value = "idPlanet", required = false) String idPlanet) {
if (idPlanet != null){
Planet planet = planetService.getById(Integer.parseInt(idPlanet));
model.addAttribute("planet", planet);
}
List<Satellite> satellites = satelliteService.findAll();
model.addAttribute("satellites", satellites);
return new RedirectView("./addPlanet");
}
As you can see I am trying to do the RedirectView to the JSP called addPlanet.jsp.
I have also tried this url (among others): "../webapp/WEB-INF/jsp/addPlanet.jsp", I am convinced that it is a rookie nonsense, but I am unable to see the error
I have also tried to create another servlet and retrieve the object I need through the #ModelAtribute, but the object added in the first servlet is lost in the process, this is the code:
#GetMapping("/updatePlanet")
#ResponseBody
String update(Model model, #ModelAttribute("planet") Planet planet){
model.addAttribute("planet",planet);
return "addPlanet";
}
This wat sends the user to the addPlanet.jstl, but the object obtained by this method is an object just created by the constructor with attributes with the value of null or 0
Finally I found the solution, here it is:
#GetMapping("/planetForm/{idPlanet}")
public String toPlanetForm(Model model, #PathVariable(value = "idPlanet", required = false) String idPlanet) {
if (idPlanet != null){
Planet planet = planetService.getById(Integer.parseInt(idPlanet));
model.addAttribute("planet", planet);
}
List<Satellite> satellites = satelliteService.findAll();
model.addAttribute("satellites", satellites);
return "addPlanet";
}
As you can see I had to change the #GetMapping for a new URL, now the function returns a String which is the name of the JSP without extension. In addition to the parameter of the function #RequestParam I have had to change it to#PathVariable, which its value is the same as the mustache expression of #GetMapping
In PHP there is the possibility to recognize a parameter in the address bar by passing it in the controller's method ; for example :
http://192.168.2.49/papsp/index.php/meeting/modif/3
In this example the data 3 is taken as parameter value for the meeting controller's method modif :
public modif($key) { ... }
So how to proceed analogically in Spring ?
You need to use the #RequestMapping annotation, along with #PathVariable with your method param. And your url will be like this /meeting/modif/{key}.
Here's how should be your code:
#RequestMapping(value = "/meeting/modif/{key}", method = RequestMethod.POST)
public void modif(#PathVariable int key) {
Can you give me a brief explanation and a sample in using #PathVariable in spring mvc? Please include on how you type the url?
I'm struggling in getting the right url to show the jsp page. Thanks.
suppose you want to write a url to fetch some order, you can say
www.mydomain.com/order/123
where 123 is orderId.
So now the url you will use in spring mvc controller would look like
/order/{orderId}
Now order id can be declared a path variable
#RequestMapping(value = " /order/{orderId}", method=RequestMethod.GET)
public String getOrder(#PathVariable String orderId){
//fetch order
}
if you use url www.mydomain.com/order/123, then orderId variable will be populated by value 123 by spring
Also note that PathVariable differs from requestParam as pathVariable is part of URL.
The same url using request param would look like www.mydomain.com/order?orderId=123
API DOC
Spring Official Reference
Have a look at the below code snippet.
#RequestMapping(value="/Add/{type}")
public ModelAndView addForm(#PathVariable String type) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("addContent");
modelAndView.addObject("typelist", contentPropertyDAO.getType() );
modelAndView.addObject("property", contentPropertyDAO.get(type,0) );
return modelAndView;
}
Hope it helps in constructing your code.
If you have url with path variables, example www.myexampl.com/item/12/update where 12 is the id and create is the variable you want to use for specifying your execution for instance in using a single form to do an update and create, you do this in your controller.
#PostMapping(value = "/item/{id}/{method}")
public String getForm(#PathVariable("id") String itemId ,
#PathVariable("method") String methodCall , Model model){
if(methodCall.equals("create")){
//logic
}
if(methodCall.equals("update")){
//logic
}
return "path to your form";
}
#PathVariable used to fetch the value from URL
for example: To get some question
www.stackoverflow.com/questions/19803731
Here some question id is passed as a parameter in URL
Now to fetch this value in controller all you have to do is just to pass #PathVariable in the method parameter
#RequestMapping(value = " /questions/{questionId}", method=RequestMethod.GET)
public String getQuestion(#PathVariable String questionId){
//return question details
}
Annotation which indicates that a method parameter should be bound to a URI template variable. Supported for RequestMapping annotated handler methods.
#RequestMapping(value = "/download/{documentId}", method = RequestMethod.GET)
public ModelAndView download(#PathVariable int documentId) {
ModelAndView mav = new ModelAndView();
Document document = documentService.fileDownload(documentId);
mav.addObject("downloadDocument", document);
mav.setViewName("download");
return mav;
}
Let us assume you hit a url as www.example.com/test/111 .
Now you have to retrieve value 111 (which is dynamic) to your controller method .At time you ll be using #PathVariable as follows :
#RequestMapping(value = " /test/{testvalue}", method=RequestMethod.GET)
public void test(#PathVariable String testvalue){
//you can use test value here
}
SO the variable value is retrieved from the url
It is one of the annotation used to map/handle dynamic URIs. You can even specify a regular expression for URI dynamic parameter to accept only specific type of input.
For example, if the URL to retrieve a book using a unique number would be:
URL:http://localhost:8080/book/9783827319333
The number denoted at the last of the URL can be fetched using #PathVariable as shown:
#RequestMapping(value="/book/{ISBN}", method= RequestMethod.GET)
public String showBookDetails(#PathVariable("ISBN") String id,
Model model){
model.addAttribute("ISBN", id);
return "bookDetails";
}
In short it is just another was to extract data from HTTP requests in Spring.
have a look at the below code snippet.
#RequestMapping(value = "edit.htm", method = RequestMethod.GET)
public ModelAndView edit(#RequestParam("id") String id) throws Exception {
ModelMap modelMap = new ModelMap();
modelMap.addAttribute("user", userinfoDao.findById(id));
return new ModelAndView("edit", modelMap);
}
If you want the complete project to see how it works then download it from below link:-
UserInfo Project on GitLab
I am new to Spring and Rest Endpoints.
I have a controller, which accepts #RequestParam and returns a JSON Response.
By default the #RequestParam required = "true", which is how I need it.
I am using Spring 3.1.3
This is my Get Method in the controller:
#Controller
#RequestMapping("/path")
public class MyController{
#RequestMapping(value = "/search/again.do", method = RequestMethod.GET, produces = {
"application/json"
})
public ResponseEntity<?> find(#RequestParam(value = "test", required = true) final String test) {
return new ResponseEntity<String>("Success ", HttpStatus.OK);
}
}
When I send a get with the request param it hits the endpoint , which is how I expect.
Example : path/search/again.do?test=yes
Everything is perfect.
This is where I am having issue:
When I send a Get with that value missing:
Example: path/search/again.do
I get a 400 Bad Request. May be this is correct.
But what I want to achieve is. When the required value is missing in the GET request.
I can send a JSON response as that #RequestParam Value test is missing.
Can anybody guide me how to achieve this.
I am not sure what I am missing.
Thanks in advance.
If you look closely at your code, you'll see that the answer is staring right at you. Just change required to false and you should be good to go. When the user doesn't provide a value for GET parameter test, then you can return a special message.
#Controller
#RequestMapping("/path")
public class MyController {
#RequestMapping(value = "/search/again.do", method = RequestMethod.GET, produces = {
"application/json"
})
public ResponseEntity<?> find(#RequestParam(value = "test", required = false) final String test) {
if (test == null) {
return new ResponseEntity<String>("test parameter is missing", HttpStatus.OK);
}
else {
return new ResponseEntity<String>("Success ", HttpStatus.OK);
}
}
}
Solution 1: You can use custom #ExceptionHandler in your controller, e.g
#ExceptionHandler(MissingServletRequestParameterException.class)
public ResponseEntity<?> paramterValidationHandler(HttpServletResquest request){
//validate the request here and return an ResponseEntity Object
}
Solution 2: Would be custom spring ErrorController which I never have tried myself but it possible to override it.
Solution 3: You can write an ControllerAdvice for a global controller exception handling.
Well if you set the parameter test is required. U just can't send the request without that param. Try to change the param required= false and handle the missing param in the method. You can us something likeif(test==null) throw new Exception("Param test missing")
The question sounds weird, I'm playing around with Spring MVC and am trying to move between two pages and basically I'm creating a JSP page using Spring Form JSTL's so it just uses a POST, and I use a controller to move from one page to the next. But Models are lost from page to page, and I'd like to hide the actual variable so QueryStrings are out of the question(as
far as I know). I know I can use a InternalResourceView, but only allows me to use a model.
I want to transfer a variable that will be exclusive to that page, what's the best way without a model or using QueryStrings?
I was planning on using SessionAttribute to easily define them, but was wondering, how do you remove a SessionAttribute created variable? I tried HttpSession.removeAttribute and it didn't seem to work.
You can also use SessionStatus.setComplete() like this:
#RequestMapping(method = RequestMethod.GET, value="/clear")
public ModelAndView clear(SessionStatus status, ModelMap model, HttpServletRequest request) {
model.clear();
status.setComplete();
return new ModelAndView("somePage");
}
or DefaultSessionAttributeStore.cleanUpAttribute like this:
#RequestMapping(method = RequestMethod.GET, value="/clear")
public ModelAndView clear(DefaultSessionAttributeStore status, WebRequest request, ModelMap model) {
model.remove("mySessionVar");
status.cleanupAttribute(request, "mySessionVar");
return new ModelAndView("somePage");
}
I use it like this on one of my forms that has mulitple sessionAttributes and I want to remove only one of them.
Yes... HttpSession.removeAttribute
You can use the removeAttribute method from the HttpSession class.
you can use WebRequest.removeAttribute(String name, int scope) that works with Spring #SessionAttributes. Quote from #SessionAttributes javadoc - "Alternatively, consider using the attribute management capabilities of the generic {#link org.springframework.web.context.request.WebRequest} interface."
Also look at my example.
#Controller
#SessionAttributes({"sessionAttr"})
public class MyController {
#ModelAttribute("sessionAttr")
public Object defaultSessionAttr() {
return new Object();
}
#RequestMapping(value = "...", method = RequestMethod.GET)
public String removeSessionAttr(WebRequest request, Model model) {
request.removeAttribute("sessionAttr", WebRequest.SCOPE_SESSION);
model.addAttribute("sessionAttr", defaultSessionAttr());
return "myView";
}
}