Spring SimpleFormController with annotations in referenceData - spring

How can i write referenceData method with SpringFormController annotations.I have several java.util.Map objects ,Finally i am setting all these objects in coomand object.How to return this object by using Spring Form Controller.
Initially I am displaying form using below code:
#RequestMapping(method=RequestMethod.GET)
public String initForm(Model map){
TestDTO test=new TestDTO();
map.attribute("cmdtest",test);
return "test";
}
#ModelAttribute("customer")
public Model setup(Model map,HttpServletRequest request)
{
Map testData=testService.getTestData(request)
model.addAttribute("testData",testData);
return model;
}
How to access testData map object in my jsp page?
Regards,
Raj

The map is available to the jsp page as customer.testData; "customer" because that's what you named your ModelAttribute and "testData" because that's what you named it in the model.
<p>Here is your testData: ${customer.testData}</p>

Related

Spring MVC autobinding can not access map data in thymeleaf

I am new to java and was trying to test thymeleaf in springboot.
with code like the first controller I can access the data in a map through thymeleaf
but can not access the data in a map by the second controller.
why declaring map like 2nd method can't work?
can someone help me? thx
public class ViewController {
public String index(Map<String, Object> map) {
map.put("hello","Bonjour");
map.put("Users", Arrays.asList("Ken","Yu","JY"));
return "index";
}
}
public class ViewController {
public String index() {
Map<String, Object> map=new HashMap<String, Object>();
map.put("hello","Bonjour");
map.put("Users", Arrays.asList("Ken","Yu","JY"));
return "index";
}
}
Springboot follows the Model View Controller (MVC) architecture . Simply put Models are used to supply attributes to the view to be rendered.Here you are using thyme-leaf as the view renderer while the model is fed into the thyme-leaf template.Model, ModelMap, and ModelAndView are used to define a model in a Spring MVC application.Spring boot automatically takes care of binding the view and the model together.
As such springboot #RequestMapping handler method expects the method argument for model as :
java.util.Map / org.springframework.ui.Model /
org.springframework.ui.ModelMap for enriching the implicit model that
is exposed to the web view.
Doc
So if you provide a map as a method parameter it is automatically bound the view.In your second case that it not happening automatically .That is the reason second method does not work.Example using ModelAndView :
#GetMapping("/goToIndexPage")
public ModelAndView methodWithModelAndViewReturn() {
ModelAndView modelAndView = new ModelAndView("index");
modelAndView.addObject("message", "Hello");
return modelAndView;
}

How to pass model attributes between method inside controller Spring MVC

Good day folks.
I have couple methods inside controller I want to pass model attributes between them,
First method gets data from a database:
#RequestMapping(value="/result", method=RequestMethod.GET)
public String resultHTML(#RequestParam String name, #ModelAttribute("fbosAttributes") FormBackingObjectSearch fbos,BindingResult bindingResult, Model model) throws Exception {
model.addAttribute("findAttributes", educationWebService.fetchByNam(fbos.getName()));
return "search";
And another method have to get attributes witch was created from method above:
#RequestMapping(value="/result.xls", method=RequestMethod.GET)
public String resultXLS(#ModelAttribute("findAttributes") ArrayList<FormDate> mylists, Model model) throws Exception {
model.addAttribute("findAttributesNew", mylists);
return "xlspage";
}
when I check for mylists.size() it shows/returns 0
Please help.
You can add session attributes to your controller class by this annotation:
#SessionAttributes({"findAttributes"})

Retrieving values from jsp without using pojo variables

We can get the values of a submitted form in a jsp page in controller using request.getParamenter(xxxx),by using commandName or by using hidden fields.
is there any other way to get values from a form of jsp in a controller?
Spring provides several ways of databinding parameters in your request to actual objects in Java. Most of the databinding is specified using annotated methods or by annotating paramters within methods.
Lets consider the following form:
<form>
<input name="firstName"/>
<input name="lastName"/>
<input name="age"/>
</form>
In a Spring controller the request parameters can be retreived in several ways.
#RequestParam Documentation
#RequestMapping("/someurl)
public String processForm(#RequestParam("firstName") String firstName,
#RequestParam("lastName") String lastName,
#RequestParam("age") String int,) {
.....
}
If our request parameters are modeled in a class Person.java we can use another technique, #ModelAttribute.
Person.java
public class Person(){
String firstName;
String lastName;
int age;
//Constructors and Accessors implied.
}
#ModelAttribute Documentation
#RequestMapping(value="/someUrl")
public String processSubmit(#ModelAttribute Person person) {
//person parameter will be bound to request parameters using field/param name matching.
}
These are two of the most commonly used methods Spring uses to provide databinding. Read up on others in the Spring MVC Documentation.
public String myMethod(#RequestParam("myParamOne") String myParamOne) {
//do stuff
}
You can directly map fields to controller method by annotation #RequestParam or you can directly bind object using #ModelAttribute.
public ModelAndView method(#RequestParam(required = true, value = "id") Long id) {
}
public ModelAndView method(#ModelAttribute("pojo") POJO pojo, BindingResult results) {
}

Intercepting the #responsebody in spring mvc

I have a Spring MVC web application with conroller like below :
#Controller
public class ActionRestController {
#RequestMapping(value = "/list", method = GET)
#ResponseBody
public List<Action> list(Action action, SearhCriteria searchCriteria) {
List<Action> ret = new ArrayList<Action>();
// Call a service method to get the records
// Copy the records into the list
// return the list of objects
return ret;
}
The Controller is invoked when the user does a search. There are several such controllers in the app, one for each searchable entity.
For reasons that I cannot explain very well, here, I cannot modify these controllers in anyway.
But now, I have requirement in the UI to display the search criteria and the no. of records and paging details, as well. This information is not returned by the controller. The JSON returned by the Controller contains just the list of records.
I have put up a different controller which will handle the request, gets and puts the extra info in the model and forwards the request to the existing controller like below :
#Controller
public class ActionExtendedController {
#RequestMapping(value = "/searchlist", method = GET)
#ResponseBody
public List<Action> list(Action action, SearhCriteria searchCriteria, Model model) {
model.addAttribute("searchParameters", searchCriteria);
return "forward:/list";
}
Upto this point, all is well.
What I want to do is intercept the request at a point where the List is returned from the controller, before it is converted to JSON, and return a map containing the list and the search parameters.
Now since the 'immutable' controller users ResponseBody the control goes to the JacksonMessageConverter amd the response goes out from there. I have already tried the following paths and they do not work.
Interceptor - By the time I get here, the response is already written out, so there is no way to change it.
Custom ObjectMapper for the JasksonMessageConverter - Will not work, since I do not have access to the model object inside the mapper, I only have access to the list returned by the controller.
Aspect #After pointcut for the controller - I think this technique will work, but I cannot get it to work. The advise does not fire and I am sure I am missing something in the configuration.
Is there a way to get Spring AOP to fire on a annotated controller, handler method or
can anyone suggest another method of intercepting the handler return value (along with the model) ?
How about a simple delegation to the base controller in your extended controller:
#Controller
public class ActionExtendedController {
#Autowired ActionRestController baseRestController;
#Autowired MappingJacksonJsonView mappingJacksonJsonView;
#RequestMapping(value = "/searchlist", method = GET)
public View list(Action action, SearhCriteria searchCriteria, Model model) {
List<Action> actions = baseRestController.list(action, searchCriteria, model);
model.addAttribute("actions", actions);
model.addAttribute("searchParameters", searchCriteria);
return mappingJacksonJsonView;
}
this way you are delegating to the original controller, but using this new controller for the view. Just register a mappingJacksonJsonView as a bean also which will serialize all model objects (searchcriteria and actions) into the json view. You need not even return a view but can also use #ResponseBody, with a type that can hold the responses and search criteria.
Why don't you change the return type to a Map? Like:
#Controller
public class ActionRestController {
#RequestMapping(value = "/list", method = GET)
#ResponseBody
public Map<String, Object> list(Action action, SearhCriteria searchCriteria) {
Map<String, Object> map = new HashMap<String, Object>();
List<Action> ret = new ArrayList<Action>();
// Call a service method to get the records
// Copy the records into the list
// return the list of objects
map.put("searchResult",ret);
map.put("searchCriteria", searchCriteria);
return map;
}

I am confused about how to use #SessionAttributes

I am trying to understand architecture of Spring MVC. However, I am completely confused by behavior of #SessionAttributes.
Please look at SampleController below , it is handling post method by SuperForm class. In fact, just field of SuperForm class is only binding as I expected.
However, After I put #SessionAttributes in Controller, handling method is binding as SubAForm. Can anybody explain me what happened in this binding.
-------------------------------------------------------
#Controller
#SessionAttributes("form")
#RequestMapping(value = "/sample")
public class SampleController {
#RequestMapping(method = RequestMethod.GET)
public String getCreateForm(Model model) {
model.addAttribute("form", new SubAForm());
return "sample/input";
}
#RequestMapping(method = RequestMethod.POST)
public String register(#ModelAttribute("form") SuperForm form, Model model) {
return "sample/input";
}
}
-------------------------------------------------------
public class SuperForm {
private Long superId;
public Long getSuperId() {
return superId;
}
public void setSuperId(Long superId) {
this.superId = superId;
}
}
-------------------------------------------------------
public class SubAForm extends SuperForm {
private Long subAId;
public Long getSubAId() {
return subAId;
}
public void setSubAId(Long subAId) {
this.subAId = subAId;
}
}
-------------------------------------------------------
<form:form modelAttribute="form" method="post">
<fieldset>
<legend>SUPER FIELD</legend>
<p>
SUPER ID:<form:input path="superId" />
</p>
</fieldset>
<fieldset>
<legend>SUB A FIELD</legend>
<p>
SUB A ID:<form:input path="subAId" />
</p>
</fieldset>
<p>
<input type="submit" value="register" />
</p>
</form:form>
When processing POST request, Spring does the following:
Without #SessionAttributes: Spring instantiates a new instance of SuperForm (type is inferred from the signature of register()), populates its properties by values from the form fields and passes it to the register() method.
With #SessionAttributes: Spring obtains an instance of model attribute from the session (where it was placed when processing GET due to presence of #SessionAttributes), updates its properties by values from the from fields and passes it to the register() method.
That is, with #SessionAttributes , register() gets the same instance of the model attribute object that was placed into the Model by getCreateForm().
Adding on to what #axtavt said: Suppose, in getCreateForm you are putting some values for a drop-down (list or map), or you are putting some values in form that you want in register method but you don't want them to show in form (not even in hidden fields). Now suppose that an error occurred in register method and you need to show the form again. To populate drop down values and other values that you would need in next post, you would have to repopulate them in form. The #SessionAttribute helps here as #axtavt very well described above.
#Controller
#SessionAttributes("test")
public class Controller{
Customer customer;
public Controller() {
super();
customer = new Customer();
}
#ModelAttribute("test")
public Customer getCustomer() {
customer.setName("Savac");
return customer;
}
#RequestMapping({"/index"})
public ModelAndView showMainPage (#ModelAttribute("test") Customer customer, ModelMap model, method = RequestMethod.GET) {
//in the view you set the name
return new ModelAndView("index");
}
#RequestMapping(value = "customer/{customerID}", method = RequestMethod.GET)
public ModelAndView viewAdvice(#PathVariable("customerID") int customerID, #ModelAttribute("test") Customer customer, ModelMap model) {
customer.setName("AnotherName");
model.addAttribute("test", customer);
return new ModelAndView("customer");
}
}
According to Spring reference documentation #ModelAttribute annotated method argument is resolved as follows:
Retrieve from model object if it is present (normally added via #ModelAttribute annotated methods)
Retrieve from HTTP session by using #SessionAttributes.
Create using URI path variable that matches the #ModelAttribute name through a converter
Create using default constructor and add it to Model.
A handler class can be annotated with #SessionAttributes with a list of names as its arguments. This is to instruct Spring to persist (in session) those data items present in the model data which match the names specified in #SessionAttributes annotation.
Thus in the SampleController, the post method's #ModelAttribute argument is resolved with #SessionAttributes field due to the resolution method mentioned above.

Resources