From my controller I set my Model and view like:
ModelAndView mav = new ModelAndView();
mav.setView("index");
mav.addObject("user", user);
mav.addObject("someCollection", someCollection);
return mav;
Now I want to create a helper type object that will take the someCollection and the user object as parameters.
My helper function will output some HTML etc., is this possible?
You can write macros and directives using FTL or Java, expose them to your templates and invoke them same way you normally do with built-in macros/directives.
Nothing prevents you from putting any Java object, e.g. a helper instance, to the model and then call a method of it using the syntax like this: ${helper.myMethod(arg)}.
/**
* Add logotype logotype1AsBase64.
* #return
* #throws IOException
#ModelAttribute("logotype1AsBase64")
public String getLogotype()
throws IOException {
return logotypeService.getLogotype();
}
*/
#ModelAttribute
public void addAttributes(Model model) throws IOException {
//...
model.addAttribute("logotype1AsBase64", logotypeCacheServ.getImage("logotypeInEnglish1From20190101.png"));
//...
}
Then to use it:
<img src="<#if locale == 'specificLocale'>${logotype1AsBase64}></#if>" alt="description for picture">
And the model attribute can contain more html other than base64 for logotype, if the setup is as such.
Related
I have a spring MVC based application and I want to add a functionality in which some of my controllers will return the same view depending on the value of a parameter.
#RequestMapping("/someView")
public String returnView(Model model, HttpServletRequest request, String param){
if(param.equals("condition")){
return "commonView";
}
// do stuff
return "methodSpecificView";
}
Is there a way in which the first if condition can be configured in an xml? Since similar functionality needs to implemented in many controllers and I don't want to write boilerplate code an xml configuration can make things simpler.
Furthermore, if the first one is possible, can it be extended to eliminate the parameter param from request mapping method signature and put that in xml too?
You can use #RequestMapping:
#RequestMapping(value = {"/someView", "/anotherView", ...}, params = "name=condition")
public String returnCommonView(){
return "commonView";
}
In Spring 3.2 which is annotation based the below code snippet will give you an idea for your problem:
#RequestMapping("formSubmit.htm")
public String onformSubmit(#ModelAttribute("TestBean") TestBean testBean,BindingResult result, ModelMap model, HttpServletRequest request) {
String _result = null;
if (!result.hasErrors()) {
_result = performAction(request, dataStoreBean);//Method to perform action based on parameters recieved
}
if(testBean.getCondition()){
_result = "commonView";
}else{
_result = "methodSpecificView";
}
return _result;
}
TestBean//Class to hold all the required setters and getters
Explanation:
As the request from your view comes to this method the ModelAttribute reference will hold all the values from view if the condition is obtained from the view than you can directly obtain it from model attribute and return the corresponding view.
If your condition is obtained after applying certain logic than you can set the condition in the testBean and again get it to return the corresponding view.
You should consider implementing this via AOP - Around advice something like below.
#Around("#annotation(RequestMapping)") // modify the condition to include / exclude specific methods
public Object aroundAdvice(ProceedingJoinPoint joinpoint) throws Throwable {
Object args[] = joinpoint.getArgs();
String param = args[2]; // change the index as per convenience
if(param.equals("condition")){
return "commonView";
} else {
return joinpoint.proceed(); // this will execute the annotated method
}
}
I am referring the example from here
where the #ModelAttribute is placed at the method level
/**
* Retrieves all addresses and allows them to be used as a model
* #return a model attribute containing addresses
*/
#ModelAttribute("addresses")
public List<Address> getAllAddresses() {
// Delegate to service
return addressService.getAll();
}
#InitBinder
public void initBinder(WebDataBinder webDataBinder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-mm-dd");
dateFormat.setLenient(false);
webDataBinder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
}
/**
* Handles and retrieves a JSP page containing all addresses.
* We use the #ModelAttribute to pass the data to the view
*
* #return the name of the JSP page
*/
#RequestMapping(value="list1", method = RequestMethod.GET)
public String getAllUsingModelAttribute() {
logger.debug("Received request to show all addresses page");
// No need to add the model here
// It has been automatically added when we used the #ModelAttribute annotation earlier
// The name of the ModelAttribute is "addresses". Your JSP should reference "addresses"
// This will resolve to /WEB-INF/jsp/addressespage.jsp
return "addressespage";
}
My question is, is the method annotated with #ModelAttribute autofired when the request comes to the controller? In this case method getAllAddresses(). As in the example I don't see this method called explicitly anywhere.
Or it is fired when the request comes to the method immediately placed after it containing #RequestMapping?
Same question for #initBinder is the method annotated with it autofired after form submission?
When a page is going to render if the page has a form which has been made by form taglib using Spring like:
<form:form commandName="addresses" method="post">
this lead your page to look for a proper #ModelAndAttribute with name 'addresses'. If your program was able to find that (like the one you have defined)
#ModelAttribute("addresses")
public List<Address> getAllAddresses() {
// Delegate to service
return addressService.getAll();
}
that make a model available for your form with a List ready to change !
then you can use another method for submitting the form like this:
#RequestMapping(value="path", method=RequestMethod.POST)
public String doSomethingForMe(#Valid #ModelAttribute("addresses") List <Address>, BindingResult result) {
if(result.hasErrors()){
return "TO_THE_PAGE_YOU_WANT_FOR_SHOWING_THE_ERROR_TO_USER";
}
// do the other stuffs you want !
}
I just write this code here, so sorry if you found out any typo problem but that's the story !
Good Luck !
Try to debug your controller and put some logging statements.
The first things you culd see is the call to #ModelAttribute annotated method.
Your initBinder will be called if you put a custom object into Model or if your handler method declare a custom Object as parameter.
#ModelAttribute("obj")
public List<Address> getAllAddresses() {
// Delegate to service
return new CustomObject();
}
#RequestMapping(value="list1", method = RequestMethod.GET)
public String getAllUsingModelAttribute(CustomObject customObject) {
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}" />
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.
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";
}
}