I'm using a multiple select HTML form input to allow a user to pick a collection of Extensions from a list of all possible Extensions.
The Extension class is quite simple -
public class Extension {
private String number;
private String firstName;
private String lastName;
... getters and setters ...
#Override
public String toString() {
return new StringBuilder(number).append(" - ")
.append(firstName).append(" ").append(lastName)
.toString();
}
}
Here's my form object -
public class BusinessUnitForm {
private String name;
private Collection<Extension> extensions;
public Collection<Extension> getExtensions() {
return extensions;
}
public void setExtensions(Collection<Extension> extensions) {
this.extensions = extensions;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
And the controller -
#Controller
#RequestMapping("/businessunit")
public class BusinessUnitController {
... extension service & getters/setters ...
#RequestMapping(method = RequestMethod.GET)
public ModelAndView showForm(HttpServletRequest request, HttpServletResponse response) throws Exception {
Integer customerId = (Integer) request.getSession().getAttribute("customerId");
ModelAndView mav = new ModelAndView("bu");
// this is quite expensive...
Collection<Extension> allExtensions = extensionService.getAllExtensions(customerId);
BusinessUnitForm businessUnitForm = new BusinessUnitForm();
mav.addObject("allExtensions", allExtensions);
mav.addObject("businessUnitForm", businessUnitForm);
return mav;
}
#RequestMapping(value="/create", method = RequestMethod.POST)
public ModelAndView create(HttpServletRequest request, HttpServletResponse response, BusinessUnitForm businessUnitForm, BindingResult result) throws Exception {
// *** BREAKPOINT HERE *** to examine businessUnitForm
Integer tenantId = (Integer) request.getSession().getAttribute("tenantId");
// code to process submission
ModelAndView mav = new ModelAndView("bu");
return mav;
}
}
And finally the view -
<%# page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%# taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%# taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<%# taglib uri="http://www.springframework.org/tags" prefix="spring" %>
<html>
...
<form:form action="businessunit/create" method="POST" commandName="businessUnitForm" >
<form:label path="name"></form:label><form:input path="name" />
<form:select path="extensions" cssClass="multiselect">
<form:options items="${allExtensions}" itemValue="number" />
</form:select>
<input type="submit" value="Create" />
</form:form>
...
</html>
At the breakpoint shown above in the create controller method, businessUnitForm.extensions is null. businessUnitForm.name is bound correctly.
I've tried, perhaps misguidedly, making businessUnitForm.extensions a LazyList but this doesn't help.
If I change BusinessUnitForm.extensions to be a Collection of unspecified type, it is populated successfully with a LinkedHashSet of Strings, containing the values selected.
Maybe I'm expecting too much of Spring, but I was hoping it would be able to use the values from the select, and also the reference data in allExtensions to automagically create a Collection<Extension> for me on the businessUnitForm. I understand the role of CustomCollectionEditors, but was under the impression that this might not be required in Spring 3.
Can Spring 3 populate my Collection<Extension> on the BusinessUnitForm without me writing a custom collection editor ? Some kind of trick with the view, perhaps ?
Thanks in advance ...
Dan
You need to implement a custom converter that is able to convert the String from the request into an Extension object.
And then you must use Collection (or List, or Set) with generic type information.
See this answer for an example of an converter: Submit Spring Form using Ajax where Entity has Foreign Entities
Related
I am trying to send object of User class to success.jsp. But getting null when trying to retrieve the object in success.jsp.
Code for UserController:
#Controller
#RequestMapping("/user")
public class UserController {
#PostMapping("/login")
public String Register(#Valid #ModelAttribute("user") User user,Errors errors,Model model) {
System.out.println("....done....");
if(errors.hasErrors()) {
return "user";
}
else {
RegisterService.show(user);
model.addAttribute("user",user);
return "redirect:/success";
}
}
}
Code for success.jsp
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%# page import="com.company.models.User" %>
<body>
Registration Successful
<%
User user=(User)request.getAttribute("user");
System.out.println("user="+user);
%>
</body>
you can use RedirectAttributes to send data to the page even if you are redirecting.
example:
#PostMapping("/login")
public String Register(#Valid #ModelAttribute("user") User user,Errors errors, RedirectAttributes attributes) {
System.out.println("....done....");
if(errors.hasErrors()) {
return "user";
}
else {
RegisterService.show(user);
attributes.addFlashAttribute("user", user);
return "redirect:/success";
}
}
read the documentation at: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/mvc/support/RedirectAttributes.html
It was because I was sending a redirect to success.jsp. So cannot pass data
Could you please assist me for the following code? I am trying to get ENUM values into dropdown but dropdown displayes nothing.
create.jsp
<select name="labOwner" name="labOwner" id="labOwner">
<option value="Select"></option>
<c:forEach var="labOwner" items="${labOwner}">
<li>${labOwner}</li>
</c:forEach>
</select>
LabController.java
#RequestMapping(value = "/lab/labOwner")
public ModelAndView getPages(){
List<LabOwner> labOwner = new ArrayList<LabOwner>( Arrays.asList(LabOwner.values() ));
ModelAndView model = new ModelAndView("create");
model.addObject("labOwner", labOwner);
return model;
}
LabOwner.java
public enum LabOwner {
G_ONLY("G"),
D_ONLY("D"),
GS("S/D ");
private String labOwner;
LabOwner(String labOwner) {
this.labOwner = labOwner;
}
public String getLabOwner() {
return labOwner;
}
You can use the spring form tag to bind your property:
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<form:select path="labOwnerBeanPropertyNameHere" id="labOwner">
<c:forEach var="labOwnerValue" items="${labOwner}">
<form:option value="${labOwnerValue}">${labOwnerValue}</form:option>
</c:forEach>
</form:select>
Note that you'll want to display the value of each item in your labOwner list, rather than the list as a whole.
Also, your controller code can be simplified to:
#GetMapping("/lab/labOwner")
public String getPages(Model model){
model.addAttribute("labOwner",
new ArrayList<LabOwner>(Arrays.asList(LabOwner.values());
return "create";
}
Finally, take a look at Project Lombok and use the #Getter annotation for your Enum class.
When I use <form:input path="name" /> inside my jsp page it show HTTP Status 500 Error.
The issue that I'm facing is because of this tag <form:input path="name"> But If I remove this tag and use normal input tag it's working fine for me.
Any Help will be Appreciated.
I Also Include Taglib for form
<%# taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
My Jsp file is
Code Inside My controller is
and The Error it's displaying to me is
Use ModelAndView like below and create a bean with setters and getters of property "name".
#RequestMapping(value = "/insert", method = RequestMethod.GET)
public ModelAndView insert() {
return new ModelAndView("script", "command" , new MyBean());
}
#RequestMapping(value = "/insert", method = RequestMethod.POST)
public ModelAndView attackHandler(#ModelAttribute("myBean")MyBean mybean) {
System.out.println(mybean.getName());
return new ModelAndView("script", "command" , mybean);
}
Please provide the Bean(with setter and getter) for you input value and Include your bean in servlet method insert and attackHandller .
like
public ModelAndView attackHandller(#ModelAttribute("beanData") #Validated BeanData beanData, BindingResult bindingResult,Model model){}
This is my controller
#Controller
#RequestMapping("VIEW")
public class SearchController {
private static final Log LOGGER = LogFactoryUtil.getLog(SearchController.class);
#RenderMapping
public String render() {
return "view";
}
#ActionMapping(params = "action = getResults")
public void getResults(#ModelAttribute("search") Search search, ActionRequest actionRequest, ActionResponse actionResponse) {
String keyword = search.getKeyword();
LOGGER.info("Keyword: " + keyword);
}
}
and my bean,
public class Search {
private String keyword;
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
}
and my view.jsp
<%#page import="org.springframework.web.bind.annotation.RequestMethod"%>
<%# taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<portlet:defineObjects />
<portlet:actionURL var = "getResultsURL">
<portlet:param name="action" value="getResults"/>
</portlet:actionURL>
<form:form action="${getResultsURL}" commandName="search" method="POST">
<form:input path="keyword"/>
<input type="submit" value="Search">
</form:form>
and I am getting the following exception
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'search' available as request attribute
It is working fine if I place #ModelAttribute("search") as a parameter in render method, but I know it was absolutely wrong(correct me)
Any suggestions?
You get this exception when the JSP page is rendered, right?
Spring MVC tells you that it cannot find "search" attribute in the current request. And indeed, your controller doesn't put any instance of Search class to the Spring MVC model.
Two options:
Create getter for Search class instance with #ModelAttribute annotation:
#ModelAttribute
public Search getSearch() {
return new Search();
}
Put Search class instance to the Spring model in the render method:
#RenderMapping
public String render(Model model) {
model.addAttribute("search", new Search());
return "view";
}
This way the form tag will find the model under the given command name.
Is there an easy way in Spring MVC 3.x to display form error messages (obtained by JSR303 validation), before submiting the form ?
Consider the example code at the end of this post.
The end-user is supposed to edit forms in which the initial data is already invalid.
Errors are properly displayed when the form is submitted (POST method), but not on initial form display (GET method).
Is there an easy way to display the errors on initial form display (GET method) ? (Is there a way to re-use the form:errors tag for this purpose?)
JSP View form1.jsp:
<%# page session="true" %>
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%# taglib uri="http://www.springframework.org/tags" prefix="s" %>
<%# taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<html><body>
<form:form commandName="form1" method="post">
<s:bind path="*">
<c:if test="${status.error}">
<div style="color: red;">There are errors:</div>
<form:errors /><br />
</c:if>
</s:bind>
<form:label path="field1" >Field1:</form:label>
<form:input path="field1" />
<form:errors path="field1" cssStyle="color: red;"/>
<br />
<form:label path="field2" >Field2:</form:label>
<form:input path="field2" />
<form:errors path="field2" cssStyle="color: red;"/>
<br />
<form:button name="submit">Ok</form:button>
</form:form>
</body></html>
Controller:
#Controller #SessionAttributes("form1")
public class Form1Controller {
#ModelAttribute("form1") public Form1Bean createForm1() { return new Form1Bean(); }
#RequestMapping(value = "/form1/edit", method = RequestMethod.GET)
public String getEdit(Model model) {
// here we pretend to get form1 from database, and store it in session.
// form1 in database may have invalid field values.
// Perform a JSR-303 validation here ?
// MAIN QUESTION: What's the easy way to add errors to model and display them ?
return "/form1";
}
#RequestMapping(value = "/form1/edit", method = RequestMethod.POST)
public String postEdit(#Valid #ModelAttribute("form1") Form1Bean form1, BindingResult result, Model model) {
if (result.hasErrors()) {
return "/form1";
} else {
return "redirect:/done";
}
}
}
Backing Bean:
public class Form1Bean {
#Size(min=4,max=10) private String field1; // getters and setters ommited for brevity
#Size(min=4,max=10) private String field2;
public Form1Bean() {
this.field1 = "bad"; this.field2="good"; // start with an invalid field1
}
//...
}
Edit: After the interpreting the answer from #jb-nizet, here is the complete controller source:
#Controller #SessionAttributes("form1")
public class Form1Controller {
#Autowired org.springframework.validation.Validator validator;
#ModelAttribute("form1") public Form1Bean createForm1() { return new Form1Bean(); }
#RequestMapping(value = "/form1/edit", method = RequestMethod.GET)
public String getEdit(#ModelAttribute("form1") Form1Bean form1, Errors errors, Model model) {
// here we pretend to get form1 from database, and store it in session.
// form1 in database may have invalid field values.
validator.validate(form1, errors);
return "/form1";
}
#RequestMapping(value = "/form1/edit", method = RequestMethod.POST)
public String postEdit(#Valid #ModelAttribute("form1") Form1Bean form1, BindingResult result, Model model) {
if (result.hasErrors()) {
return "/form1";
} else {
return "redirect:/done";
}
}
}
Made a few tests, and it seems to work! Than you #jb-nizet
Not tested, but as I understand the documentation, you would just have to inject an object of type org.springframework.validation.Validator in your controller, create and bind an Errors instance as explained in Add Error on GET METHOD Spring annotated controller, and invoke the validator's validate() method, passing the form and the Errors as argument.