Spring does not pass data between views - java

I am new to Spring MVC. I have problem regarding passing objects between views. I can pass object Flight from view "flight" to view "searchFlight" without problem. There should be no passing of any object from "searchFlight" to "bookFlight" as at this point I store needed info in static object outside of controller.
In "bookFlight" I load all the data from static object (not editable in view) and then I want to gather data in "bookFlight" and pass it to "performBook" view. Gathered data is also stored in other static object outside of controller. At this point in "performBook" I can refer to static object and display data stored in - but I can not save anything from "bookFlight" into my static object.
If I change static object to non-static (simply copy-paste flighSearch method with different metohd body) then I also can not collect data from form:form and save it in object or pass it to next view.
This is my controller. Everything in GlobalCache is public static. Every model object has setters and getters.
#RequestMapping(value = "/flight", method = RequestMethod.GET)
public ModelAndView flightSearch(ModelMap model) {
GlobalCache.flight=new Flight();
GlobalCache.flightTime=GlobalCache.generateFlightTIme()+1;
GlobalCache.flight.setTravelLength(GlobalCache.flightTime);
return new ModelAndView("flightSearch","command",new Flight());
}
#RequestMapping(value="searchFlight", method = RequestMethod.POST)
public String search(#ModelAttribute("user") Flight flight, ModelMap model) {
model.addAttribute("departureDate",flight.getDepartureDate());
model.addAttribute("departureAirport",flight.getArrivalAirport());
model.addAttribute("arrivalDate", flight.getArrivalDate());
model.addAttribute("arrivalAirport", flight.getArrivalAirport());
model.addAttribute("ticketNo", flight.getTicketNo());
model.addAttribute("travelType", flight.getTravelType());
model.addAttribute("flight", flight);
GlobalCache.flight=flight;
GlobalCache.flightTime=GlobalCache.generateFlightTIme()+1;
GlobalCache.flight.setTravelLength(GlobalCache.flightTime);
return "results";
}
#RequestMapping(value="/bookFlight", method = RequestMethod.POST)
public ModelAndView bookFLight(#ModelAttribute("user") Ticket ticket, ModelMap model) {
ticket=new Ticket();
ticket.setClassesList(classes);
ticket.setPaymentTypeList(paymentType);
ticket.setSeatPositionList(seatPosition);
ticket.setFlight(GlobalCache.flight);
ticket.setPayment(new Payment());
ticket.setUtil(new Util());
ticket.getPayment().setAmountToPay(GlobalCache.generateTicketCost());
Traveler traveler = new Traveler();
ticket.setTraveler(traveler);
model.addAttribute("ticket", ticket);
model.addAttribute("flight", GlobalCache.flight);
model.addAttribute("traveler", ticket.getTraveler());
model.addAttribute("payment", ticket.getPayment());
GlobalCache.ticket=ticket;
return new ModelAndView("book","command",GlobalCache.ticket);
}
#RequestMapping(value="performBook", method = RequestMethod.POST)
public ModelAndView booked(#ModelAttribute("user") Ticket ticket, ModelMap model) {
model.addAttribute("ticket", GlobalCache.ticket);
return new ModelAndView("booked","command",GlobalCache.ticket);
}
Example of handling form in "bookFlight" view.
<form:input path="traveler.name" value="${traveler.name}" type="text" id="5" class="form-control" aria-describedby="basic-addon1"/>
Class structure:
class Ticket{
private Flight flight;
private Traveler traveler;
private Util util;
//getters and setters and other attributes
}
At this time I do not have time to create separate controllers, hope it can be solved with just one.

Related

model.addAttribute() parameters

I'm new to Spring MVC Framework. I'm doing some self study to extend my knowledge in Java.
This is how I understand the getProducts() code definition from a tutorial I'm following but please correct me if I'm wrong.
Controller requests something from the Data Access Object >
Data Access Object gets the data from a Database or a Model through the getProductList() method > Stores the information to list > Then binds the list to the model.
So I got two question about this.
Is the inclusion of model as parameter in public String getProducts(Model model) considered the dependency injection
Is products (within quotes) in model.addAttribute("products",products); just a name which I can change to whatever I like or should it match something?
public class HomeController {
private ProductDao productDao = new ProductDao();
#RequestMapping("/")
public String home(){
return "home";
}
#RequestMapping("/productList")
public String getProducts(Model model){
List<Product> products = productDao.getProductList();
model.addAttribute("products",products);
return "productList"; //productList string is the productList.jsp which is a view
}
#RequestMapping("/productList/viewProduct")
public String viewProduct(){
return "viewProduct";
}
}
I'd appreciate any explanation or comment.
Thank you.
Yes,
model is instantiated by spring and injected to your method, means if any of model attribute matches anything in request it will be filled. and it should be the last param in the method
model.addAttribute("products",products);
"products" is just a name which you can use it in your view get the value with ${products}
My code. this is sample.
#Autowired
private ProductService productService;
#RequestMapping(value = "/settings/product")
public ModelAndView showProduct(ModelAndView mav, HttpServletRequest req, Authentication auth) {
CustomUserDetail customUserDetail = (CustomUserDetail) auth.getPrincipal();
int associationIdx = customUserDetail.getAccount().getAssociation().getIdx();
String language = CookieUtil.getCookieValue(req, "lang");
Association association = associationService.findAssociationByIdx(associationIdx);
List<AssociationProductColumnDefine> columns = associationService.findByAssociationAndLanguage(association,
language);
List<AssociationProductColumnDefine> source = associationService.findByAssociationAndLanguage(association,
"ko-kr");
mav.addObject("association", association);
mav.addObject("source", source);
mav.addObject("columns", columns);
mav.setViewName("/association/association_settings_product");
return mav;
}
Yes, you choice model and ModelAndView.
Yes, simple.

Spring preserve ModelAttribute between requests

I'm trying to achieve a loop of the following steps before save is called.
Show list
add to list
It works adding one item. On the second item added spring has lost the reference to the ModelAttribute which contained an item already and tries to reconstruct it from the form data, which it must not because it contains polymorphic types.
How do I preserve the updated model throughout every add?
Sample
#RequestMapping(value = "/foo", method = RequestMethod.GET)
public String show(#ModelAttribute("foos") ArrayList<Foo> foo, Map model) {
model.put("foo", foo);
return "foo.jsp";
}
#RequestMapping(value = "/addFoo", method = RequestMethod.POST)
public String add(#ModelAttribute("foos") ArrayList<Foo> foo,
RedirectAttributes redirectAttributes) {
foo.add(new FooImpl());
redirectAttributes.addFlashAttribute("foos", foo);
return "redirect:foo";
}
How can I do this without using SessionAttributes?

How to pass the object from one controller to another in Spring without using Session

I have a requirement where the user selects some data from a form and we need to show that selected data on the next page.
At present we are doing this with a session attribute, but the problem with this is that it overwrites the data if the first page is open in another browser tab, where the data is again selected and submitted. So I just want to get rid of this session attribute while transferring data from one controller to another.
Note: I am using an XML based Spring configuration, so please show a solution using XML, not annotations.
Define RedirectAttributes method parameter in the the handler method that handles form submission from first page:
#RequestMapping("/sendDataToNextPage", method = RequestMethod.POST)
public String submitForm(
#ModelAttribute("formBackingObj") #Valid FormBackingObj formBackingObj,
BindingResult result,
RedirectAttributes redirectAttributes) {
...
DataObject data = new DataObject();
redirectAttributes.addFlashAttribute("dataForNextPage", data);
...
return "redirect:/secondPageURL";
}
The flash attributes are saved temporarily before the redirect (typically in the session) and are available to the request after the redirect and removed immediately.
The above redirect will cause the client (browser) to send a request to /secondPageURL. So you need to have a handler method to handle this request, and there you can get access to the DataObject data set in the submitForm handler method:
#RequestMapping(value = "/secondPageURL", method = RequestMethod.GET)
public String gotoCountrySavePage(
#ModelAttribute("dataForNextPage") DataObject data,
ModelMap model) {
...
//data is the DataObject that was set to redirectAttributes in submitForm method
return "pageToBeShown";
}
Here DataObject data is the object that contains data from the submitForm method.
I worked with this requirement and I used RedirectAttributes, then you can add this redirect attributes to your model. This is an example:
#RequestMapping(value = "/mypath/{myProperty}", method = RequestMethod.POST)
public String submitMyForm(#PathVariable Long myProperty, RedirectAttributes redirectAttributes) {
redirectAttributes.addFlashAttribute("message", "My property is: " + myProperty);
return "redirect:/anotherPage";
}
#RequestMapping(method = RequestMethod.GET)
public String defaultPage(Model model, #RequestParam(required = false) String message) {
if(StringUtils.isNotBlank(message)) {
model.addAttribute("message", message);
}
return "myPage";
}
Hope it helps.
You can use RedirectAttributes ; A specialization of the Model interface that controllers can use to select attributes for a redirect scenario.
public interface RedirectAttributes extends org.springframework.ui.Model
Plus this interface also provide a way to store "Flash Attribute" . Flash Attribute is in FlashMap.
FlashMap : A FlashMap provides a way for one request to store attributes intended for use in another. This is most commonly needed when redirecting from one URL to another.
Quick Example is
#RequestMapping(value = "/accounts", method = RequestMethod.POST)
public String handle(RedirectAttributes redirectAttrs) {
// Save account ...
redirectAttrs.addFlashAttribute("message", "Hello World");
return "redirect:/testUrl/{id}";
}
Reference and detail information are here

Getting my first Spring webapp to work

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}" />

How to retain the values of the Spring MVC form backing object?

My controller has a method to return a form backing object:
#ModelAttribute(“userData”)
public UserData formBackingObject() {
return new UserData();
}
When the form submission fails its validation checks, it is redisplayed but when it is re-rendered, the userData object does not contain the user-submitted values - only the values present upon initialiation above.
#RequestMapping(method = RequestMethod.POST)
public void userData(HttpServletRequest request, #ModelAttribute(“userData”) UserData userData, BindingResult bindResult, ModelMap model) {
// do validation checks
if (bindResult.hasErrors()) {
// perform redirect back to same page
}
    return "userData";
}
You need to do a model.addAttribute("key", value) . This will help bind the values to the model object check http://static.springsource.org/spring/docs/current/spring-framework-reference/html/mvc.html for sample.
#ModelAttribute at method level is generally given to add reference data kind of data to the model. And these annotations are executed before #RequestMapping; hence your attribute "userData" is refreshed with new object before control reaches your public void userData(). method.
The solution is to add userData to the model within the method which returns your userdata form jsp to browser.

Categories

Resources