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
Related
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
I am a newbie on Spring framework and maybe this is an easy question.
I have a link as follows and attempt Spring controller handles the value"201610061023" of this link.However,my code did not work.
I know this value can be attached as a parameter or pathvariable in path but I just curious can I pass this value implicitly?
Thank you very much.
201610061023
#RequestMapping(value = "/Order")
public String requestHandlingMethod(#ModelAttribute("test") String name, HttpServletRequest request) {
return "nextpage";
}
Spring will not handle the title of the link simply because the title of the link will not be sent by the browser. To send it you can either:
add the value as parameter: 201610061023
add the value as path variable: 201610061023
add a JavaScript that will copy the title onClick into the href or send the generated URL with document.location. This can be automated, but it's pretty uncommon.
Your a-tag is wrong, you need to submit the id, there is no implicit way to submit the link-text (except a lot of java script code)!
201610061023
#RequestMapping(value = "/Order/{orderId}")
public String requestHandlingMethod(#PathVariable("orderId") long orderId, #ModelAttribute("test") String name, HttpServletRequest request) {
return "nextpage";
}
or
201610061023
#RequestMapping(value = "/Order")
public String requestHandlingMethod(#RequestParam("orderId") long orderId, #ModelAttribute("test") String name, HttpServletRequest request) {
return "nextpage";
}
See #RequestParam vs #PathVariable for the difference between this two approaches
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 hav a home controller within which i hav 2 methods one is
#RequestMapping(value = "/mypage.te", method = RequestMethod.GET)
public String mypage1(Locale locale, Model model){
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String name = auth.getName(); //get logged in username
model.addAttribute("username", name);
model.addAttribute("customGroup",grpDao.fetchCustomGroup());
model.addAttribute("serverTime", formattedDate);
model.addAttribute("username", name);
return "mypage";
}
here in this method actually i call grpDao.fetchCustomGroup() method from a Dao class which performs a native query and fetches data and returns and it is saved in customGroup.
now the same fetchcustomGroup() method is to be used in another method i.e
#RequestMapping(value = "/manageGrps.te", method = RequestMethod.GET)
public String man_grp_connections(#RequestParam("id") Integer groupId,#RequestParam("name") String groupName, Model model) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String name = auth.getName();
System.out.println("I am in the fetchCustomGroup controller");
int profileid=grpDao.getProfileId(name);
//model.addAttribute("customGroup",grpDao.fetchCustomGroup());
model.addAttribute("memberList",grpDao.fetchGroupMembers(groupId,profileid));
model.addAttribute("groupid",groupId);
model.addAttribute("profileid",profileid);
model.addAttribute("groupName",groupName);
System.out.println("groupid="+groupId);
System.out.println("groupName="+groupName);
return "manageGrps";
}
so instead of calling the fetchCustomGroup() in both the methods i just want to call in only one method and use the result in both the methods in the home controller.
so how can i use customGroup in another method to use the result of the fetchCustomGroup()
I think that what you want is to avoid executing the query twice. This can be done in different ways. The easiest way would be to assign the response to a variable in your controller and then use a getter instead of the dao. Controllers are singleton by default. Something like :
private Foo customGroup;
private synchronized Foo getCustomGroup() {
if(customGroup == null) {
customGroup = grpDao.fetchCustomGroup();
}
return customGroup;
}
And then use getCustomGroup() instead of grpDao.fetchCustomGroup()
I don't know what you are using for your persistence but using cache would also be a good idea to avoid executing the query twice.
I have a controller that gets an ID from a form in search.jsp. I want it to redirect to entitydemo.jsp, which should be able to access EntityDemo and output its attributes. How do I do that? Do I need to use redirect and put EntityDemo as a session attribute somehow?
#Controller
public class SearchEntityController {
#RequestMapping(value = "/search", method = RequestMethod.GET)
public EntityDemo getEntityDemoByID(#ModelAttribute("search") Search search, BindingResult result) {
EntityDemo entityDemo = null;
if (search.getId() != null) {
int id = Integer.parseInt(search.getId());
entityDemo = DBHelper.getEntityDemo(id);
}
return entityDemo;
}
}
Assuming that you have some class named EntityDemo which has Getters and Setters for all the fields, I think you should do something like so:
#Controller
public class SearchEntityController {
#RequestMapping(value = "/search", method = RequestMethod.GET)
public ModelAndView getEntityDemoByID(#ModelAttribute("search") Search search, BindingResult result) {
EntityDemo entityDemo = null;
Map<String, Object> model = new HashMap<String, Object>();
if (search.getId() != null) {
int id = Integer.parseInt(search.getId());
entityDemo = DBHelper.getEntityDemo(id);
model.put("entityDemo", entityDemo);
}
return new ModelAndView(new RedirectView(pageIWantToRedirectTo), model);
}
}
Then, in your JSP, you can use JSTL and do something like this: ${entityDemo.name}, where name is a field I am assuming that the EntityDemo class has together with an appropriate Getter, this being public String getName(){return this.name;}.
To my knowledge, Controller methods do not return entire objects, they either return String values which denote the name of the view, such as \foo\bar\myPage.jsp or else, entire ModelAndView objects (there are 2 types of objects, one of them has portlet in its full name and the other has servlet. In this case you must use the one that has servlet in its full name. Just for clarity, when I say full name, I mean the name which includes the package within which it resides. If memory serves me well the one you are looking for is in springframework...servlet.ModelAndView or something like that.
EDIT: If you want to redirect upon submit, then, you will need to make 2 controllers, one which will render the form and the other which will redirect once the form is submitted.
Regarding your JSP Page, you should have an xml file name dispatcher-servlet.xml. The name could be different, depending on your configurations in web.xml, but they all have the structure of <servletname>-servlet.xml. There should be a property named viewResolver (Although this should be the case, certain IDE's do not populate much for you. On the other hand, IDE's such as Netbeans set up most of the initial configuration for you). This is another controller which acts upon your views. What it does is that it automatically appends items before and after your view name which you specify in your controller. Usually it appends a prefix of pages/jsp/ and a suffix of .jsp. So, if you have a page with the following path pages/jsp/myPage.jsp, all you need to pass in your controller would be myPage. The full path to the page will be constructed by the view resolver. If you pass in the whole URL, it will still keep on adding stuff so the page still won't be found even though you specified a correct path.
I got it to work using 2 methods in my controller - one to display the form and another for the search results
Controller:
#Controller
public class SearchEntityController {
#RequestMapping(value = "/search", method = RequestMethod.GET)
public void searchForm(Model model) {
model.addAttribute(new Search());
}
#RequestMapping(value = "/entitydemo", method = RequestMethod.POST)
public void showSearchResult(#ModelAttribute Search search, Model model) {
model.addAttribute("entityDemo", getEntityDemo(search));
}
// code to load entity here
}
(Search is a class with an int id and accessors)
Form in search.jsp:
<form:form action="entitydemo" commandName="search">
ID: <form:input path="id" />
</form:form>
Showing results in entitydemo.jsp:
<core:out value="${entityDemo.foo}" /> <br/>
<core:out value="${entityDemo.bar}" />