Spring MVC form:select selection from database issue - spring

I have populated a dropdown in JSP from controller by a list using following:
'''
<form:select path="thirdPartyOccupationId" id="thirdPartyOccupationId" class="form-control input-sm">
<c:forEach var="thirdPartyProfession" items="${professionsList}">
<form:option value="${thirdPartyProfession.professionId}" label="${thirdPartyProfession.profession}" />
</c:forEach>
</form:select>
'''
thirdPartyOccupationId is from entity class. I have saved the selected value from this dropdown in database. Now when I reload the page and I don't see the value of thirdPartyOccupationId as selected. The dropdown just shows the list of the values in ascending order.
For example, I saved 5 as the value of thirdPartyOccupationId in db using the dropdown. When I reload the page the value 5 is not the selected value.
Same piece of code is working with a different field, I don't know what I am missing.
Model Classes:
ReportClass.java
#JoinColumn(name = "third_party_occupation_id", referencedColumnName = "profession_id")
#ManyToOne
private Professions thirdPartyOccupationId;
Professions.java
#Id
#Basic(optional = false)
#Column(name = "profession_id")
private String professionId;
#Column(name = "profession")
private String profession;
#OneToMany(mappedBy = "thirdPartyOccupationId")
private Collection<ReportClass> reportClassCollection;
Controller.java
reportClass.setThirdPartyOccupationId(this.serviceManager.getProfessionsService().getByKey("123"));
model.addAttribute("reportClass", reportClass);
List<Professions> professionsList = serviceManager.getProfessionsService().findAll();
model.addAttribute("professionsList", professionsList);
Appreciate any pointers.

As an workaround, I created a new row above to the <c:forEach> loop where intended to see the selected attribute, i.e.
<tr>
<td>
<c:if test="${tipFe !=null}">${tipFe}</c:if>
<c:if test="${tipFe eq null}">-</c:if>
</td>
</tr>
<tr>
<td>
<c:forEach var="ltipfe" items="${ltipfe}">
<option value=${ltipfe.tipfe}>${ltipfe.tipfe}</option>
</c:forEach>
</td>
</tr>

Related

How to send back the model data from jsp to controller

I have a controller which sets few values to a model and sends to jsp. In jsp i need to show those values(as labels) along with additional values from user as input values. When i submit the jsp i only get valid values that user has entered and the values set earlier by controller is null.
JSP
<form:form
action="${pageContext.request.contextPath}/admin/deviceAction.html"
modelAttribute="deviceData">
<table class="gridtable" width="500px">
<tr>
<td>Device Name : </td>
<td>${deviceData.deviceName}</td>
</tr>
<tr>
<td>Model Name : </td>
<td>${deviceData.modelName}</td>
</tr>
<tr>
<td>Serial No : </td>
<td>${deviceData.serialNo}</td>
</tr>
<tr>
<td>Device Id : </td>
<td>${deviceData.deviceId}</td>
</tr>
<tr>
<td>Status : </td>
<td>${deviceData.statusCode}</td>
</tr>
<tr>
<td>Action : <span class="required">*</span></td>
<td>
<form:select path="deviceAction" >
<form:option value="" label="--- Select ---" />
<form:options items="${model.actionList}" />
</form:select>
</td>
</tr>
</table>
<input type="submit" value="Submit" id="btn_submit">
</form:form>
Controller:
public ModelAndView beforeSubmit() {
ModelAndView modelView = new ModelAndView();
DeviceData deviceData = new DeviceData();
deviceData.setDevicePk("123");
deviceData.setAccessToken("abcwetrwertewrtetr");
deviceData.setDeviceId("deferterterterterwtetetertg");
deviceData.setDeviceName("test");
deviceData.setEnrolledDate("7-8-13");
deviceData.setModelName("test1");
deviceData.setSerialNo("test2dsfgdfgdfg");
deviceData.setStatusCode("test3");
List<String> actionList = getActionList();
Map<String, List<String>> model = new HashMap<String, List<String>>();
model.put("actionList", actionList);
modelView.addObject("deviceData", deviceData);
modelView.addObject("model", model);
modelView.setViewName("admin/tokenSearchResult");
}
public ModelAndView afterSubmit() {
#ModelAttribute("deviceData") DeviceData deviceData, BindingResult result) {
logger.info("#################device datas are : " + deviceData.getDevicePk() + "###### " + deviceData.getDeviceAction());
return new ModelAndView();
}
deviceData.getDevicePk() is null
Only the drop down value is having valid value. Other values displayed in the screen are received as null.
Edit:
Till now i have found only one solution:
<form:input path="deviceName" readonly="true" />
But this way UI does not looks good. The editable and non editable values mixup in the screen. Looking for a better answer
Finally i am using hidden parameters to solve the problem.
Example:
<td>${deviceData.deviceName}</td>
is replaced by:
<td><form:hidden path="deviceName"</td>
By this way it helps me to avoid any css work(which i am not much comfortable)
If anyone get a better solution kindly post it here
You need to make them into form inputs using the Spring form tags in much the same way as you have for the form:select. If they are not editable by the user, you can always disable them.
You can simple hide those input. For example :
<input type="hidden" name="VehSeriesModelId" value="${vehDetailsVM.id }">
This way, you can get the data to the controller and the user will also not be able to edit the value. On the other hand, your form will also not show it :)

How to get data from two classes that are many-to-many, in the same edit form?

I am working with two classes that have a relationship many-to-many. I insert data in both tables, the relationship is usually registered in JoinTable. My question is, how to display the data from both tables in the same form?
Here is my controller:
#Controller
public class RecipeController {
#Autowired
private ReceitaService receitaService;
#RequestMapping(value = "/novaReceita.do", method = RequestMethod.POST)
public String createRecipes(#ModelAttribute("Receita") Receita receita, BindingResult resultReceita,
#ModelAttribute("Tag") Tag tag, BindingResult resultTag, #RequestParam String action, Map<String, Object> map) {
receita.getTag().add(tag);
receitaService.addReceita(receita);
map.put("receita", receita);
map.put("receitaList", receitaService.getAllReceita());
return "listRecipes";
}
Here is where I am having problems because I can only show data for a single table.
public String editForm(#PathVariable("id") int id, ModelMap map) {
map.addAttribute("receita", receitaService.getReceita(id));
return "updateRecipes";
}
Finally, the JSP page to display the data entered:
<c:url var="url" value="/receita/${receita.id}"/>
<form:form action="${url}" method="GET" commandName="receita">
<table width=80% >
<tr>
<td><strong>ID </strong></td>
<td><form:input path="id" disabled="true" class="input-small"/></td>
</tr>
<tr>
<td><strong>Title </strong></td>
<td><form:input path="titulo" class="input-xlarge"/></td>
</tr>
<tr>
<td valign=top><strong>Desc probl</strong></td>
<td><form:textarea path="desc_prob" class="input-xlarge" rows="3" /></td>
</tr>
<tr>
<td valign=top><strong>Desc soluc</strong></td>
<td><form:textarea path="desc_soluc" class="input-xlarge" rows="6" /></td>
</tr>
<tr>
<td><strong>Tag</strong></td>
<td> <form:input path="tag" disabled="true" class="input-small"/></td>
</tr>
</table>
</form:form>
What is missing to be able to show the data from both tables?
Thank's.
For single column/property you can use <form:input/>For Many to One you can use <form:select/>For One to Many you can use <form:select multiple='true'>In your case, you have to select a single ID first for the one side of the relationship which is receita and then display all the tags in that receita, so i think it counts as One to Many at that point. So in your case, try to use this tag:<form:select path="tag" multiple="true"/>

Spring MVC: list of checkboxes not returned to controller on POST

Why doesn't the server see my list of filled checkboxes?
This question seems to be here asked many times, but the details are so different for each requester that it seems a different answer is needed each time. Here is my story.
These are my data-bearing classes. The Offer contains a list of Filter objects in the filter attribute:.
public class Offer implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id")
private Long id = null;
#Column(name="title")
private String title = null;
[snip]
#ManyToMany(fetch=FetchType.EAGER)
#JoinTable(name = "offer_filter",
joinColumns = { #JoinColumn(name = "offer_id", nullable = false, updatable = false) },
inverseJoinColumns = { #JoinColumn(name = "filter_id", nullable = false, updatable = false) })
private List<Filter> filters;
[snip]
}
public class Filter implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id")
private Long id;
#NotBlank
#Length(max=100)
#Column(name="text")
private String text;
[snip]
#Transient
private boolean owned = false;
[snip]
}
The simple controller sends the offerEdit.jsp page, with a fully-populated Offer object. The object contains a list of Filters. Because of the owned attribute, only one of the three Filters is pre-checked. This simulates my eventual plan, where the list of Filters is the whole universe and what the Offer owns is a subset.
Note the annotations, that the Offer has the filter list going to the web page but doesn't see it coming back.
public class OfferController {
[snip]
#RequestMapping(value = "/edit", method = RequestMethod.GET)
public String getEdit(#RequestParam("id") Long id, Model model, HttpSession session) {
Offer offerAttribute = offerService.get(id);
// At this point, offerAttribute.filters has three elements.
// Mockup -- tells web page that only the middle one of the three Filters should be checked.
List<Filter> filters = offer.getFilters();
Filter filter = filters.get(1);
filter.setOwned(true);
model.addAttribute("offerAttribute", offerAttribute);
return "offer/offerEdit";
}
#RequestMapping(value = "/edit", method = RequestMethod.POST)
public String postEdit(#RequestParam("id") Long id, #Valid #ModelAttribute("offerAttribute") Offer offerAttribute, BindingResult result, HttpSession session, Model model) {
// At this point, offerAttribute.filters is null.
if(result.hasErrors()) {
result.reject("offer.invalidFields");
return "offer/offerEdit";
}
offerAttribute.setId(id);
offerService.edit(offerAttribute);
return "redirect:/offer/list";
}
[snip]
}
The web page has this for its checkbox section. I use form:checkbox over form:checkboxes because I want to use a table,
[snip]
<form:form modelAttribute="offerAttribute" method="POST" action="${saveUrl}">
<table>
<tr>
<td></td>
<td><form:hidden path="id" /></td>
</tr>
<tr>
<td><form:label path="title">Title:</form:label></td>
<td><form:input path="title" size="80" /></td>
<td><form:errors path="title" cssClass="error" /></td>
</tr>
[snip]
</table>
<table>
</table>
<table>
<c:forEach items="${offerAttribute.filters}" var="filter">
<tr>
<td><form:checkbox
path="filters"
label="${filter.text}"
value="${filter.id}"
checked="${filter.owned ? 'true' : ''}" />
</td>
</tr>
</c:forEach>
</table>
[snip]
The displayed web page has three filter checkboxes displayed, with just the middle checkbox filled in.
For the returned list, I expect the server to get only the middle checkbox, which is just what I want.
Here is what the generated checkboxes look like as source:
<table style="border: 1px solid; width: 100%; text-align:left;">
<tr>
<td>
<input id="filters1" name="filters" type="checkbox" value="1"/>
<label for="filters1">Adults (18+) desired, please</label>
<input type="hidden" name="_filters" value="on"/>
</td>
</tr>
<tr>
<td>
<input id="filters2" name="filters" checked="true" type="checkbox" value="2"/>
<label for="filters2">Quiet audiences, please</label>
<input type="hidden" name="_filters" value="on"/>
</td>
</tr>
<tr>
<td>
<input id="filters3" name="filters" type="checkbox" value="4"/>
<label for="filters3">Filter Text First</label>
<input type="hidden" name="_filters" value="on"/>
</td>
</tr>
</table>
My checkbox is set, and in the HTML. To restate my question,
Why doesn't the checkbox value get seen in the controller's POST handler?
Thanks for any answers,
Jerome.
The values of checkboxes could not be directly bind to List.
To get this working you need to create a simple pojo databean that will hold the values of your form fields in jsp. And in that databean to bind the values you need to declare int[] filterId and the values of your checkboxes will bind in that array.
Hope this helps you.
After a lot of web research and different debugging sessions, I came up with a configuration I can live with.
In my controller I provide a model attribute of "filterList", containing List. The "offerAttribute" is an Offer object, containing List filters.
The view has this sequence:
<table>
<c:forEach items="${filterList}" var="filter" varStatus="status">
<tr>
<td><input type="checkbox" name="filters[${status.index}].id"
value="${filter.id}"
${filter.owned ? 'checked' : ''} /> ${filter.text}
</td>
</tr>
</c:forEach>
</table>
When the POST is done the ownerAttribute.filters list is just as long as the original filterList object that created the checkboxes. The checked ones contains a Filter.id value. The unchecked ones contain a null. (That is, the returned filters list is "sparse".) If the user clicks on just a few checkboxes then I must parse the returned list to find those that were chosen.
Once I know the ID values of the checked-on filters, I fetch each of them through Hibernate, put them into my reconstructed Offer object and then persist them to the database.
I realize that I'm not (currently) using the form:checkbox. But it works, and I'm pressed for time here. I'll come back later, perhaps, and see what form:checkbox can do for me.

How to modify a record displaying a form in a view

I am trying to accomplish the following:
I have a list of fruits, that are stored in a table with two columns "id", "name" and "color".
Next to each fruit, I got a "modify" button. What I want to do here is being able to display the fruit in a form and being able to modify the "name" and "color" attributes.
I don't understand why, but when I click the "modify" button, the form is being displayed but the properties of the fruits that I clicked are not.
Here is the code:
Controller:
#RequestMapping(value = "/fruit/modify", method = RequestMethod.POST)
public String modifyFruit( #RequestParam("id") int id, ModelMap model) {
Fruit fruit = fruitManager.getFruitById(id);
model.addAttribute("fruit", fruit);
return "redirect:/modifyfruit";
}
#RequestMapping(value = "/modifyfruit", method = RequestMethod.GET)
public String showAddForm(#ModelAttribute("fruit") Fruit fruit, ModelMap model) {
model.addAttribute("fruit", fruit);
return "/secure/modifyfruit";
}
Here is the modify button that I am displaying next to each fruit in my list:
<td>
<c:url var="modifyUrl" value="/fruit/modify.html"/>
<form id="${fruitForm}" action="${modifyUrl}" method="POST">
<input id="id" name="id" type="hidden" value="${fruit.id}"/>
<input type="submit" value="modify"/>
</form>
</td>
Here is the modifyfruit.jsp that I am using to display the form that I want to populate:
<body>
<form:form method="post" commandName="fruit">
<table width="95%" bgcolor="f8f8ff" border="0" cellspacing="0"
cellpadding="5">
<tr>
<td align="right">Name:</td>
<td><form:input path="title" value="${fruit.name}"/></td>
</tr>
<tr>
<td align="right">Color:</td>
<td><form:input path="color" value="${fruit.color}"/></td>
</tr>
</table>
<br>
<input type="submit" align="center" value="Post Ad">
</form:form>
</body>
Your redirect is simply going to that new URL without any request params being added. Therefore your fruit ID is being discarded, which is why nothing gets displayed.
The redirect seems pointless - why not return the same view name string as the GET version instead?
To redirect with the params, try:
return "redirect:/modifyfruit?id=" + id;
EDIT: just noticed you have added the Fruit to the model - this does not get transferred in a redirect and wouldn't work anyway.

Spring MVC 3 Validation will not work when attributes added to model

I'm trying to get Spring annotation based validation working in a simple webapp. I'm using Spring 3.0.5, Tiles 2.2.2. In one specific case I can get the validation error to appear next to the field, however as soon as I add any objects to the model it stops working. Ideally, after the POST, I want to redirect to a GET of the form with the validation errors included. This is the setup:
I have a simple domain object.
public class DomainObject {
#NotEmpty
private String name;
private Date created;
private Date lastModified;
...
}
I have a controller with a GET method which adds all existing DomainObjects to the model and returns a view that displays them, and contains a very simple form for creating them. It also has a POST method for creating a new DomainObject.
#Controller
#RequestMapping("/")
public class DomainObjectController {
#Autowired
private DomainObjectService domainObjectService;
#RequestMapping("form.htm")
public String home(Model model) {
model.addAttribute("objects", domainObjectService.getAll());
model.addAttribute(new DomainObject());
return "form";
}
#RequestMapping(value="new_object.do", method=RequestMethod.POST)
public String newObject(#Valid DomainObject domainObject, BindingResult bindingResult, Model model) {
if (bindingResult.hasErrors()) {
//model.addAttribute("objects", domainObjectService.getAll());
//model.addAttribute(new DomainObject());
return "form";
}
domainObjectService.saveNew(domainObject);
model.addAttribute("objects", domainObjectService.getAll());
model.addAttribute(new DomainObject());
return "form";
}
}
Here's the view:
<form:form commandName="domainObject" action="new_object.do" method="post>
<spring:message code="name" />: <form:input path="name" />
<input type="submit" value="<spring:message code="create.object"/>" /><form:errors path="name" cssClass="error"/></form:form>
</div>
<table class="centered">
<col width=50 />
<col width=225 />
<col width=200 />
<col width=200 />
<thead>
<tr>
<td id="id" class="sortable"><spring:message code="id" /></td>
<td id="name" class="sortable"><spring:message code="name" /></td>
<td id="created" class="sortable"><spring:message code="created" /></td>
</tr>
</thead>
<tbody>
<c:forEach var="obj" items="${objects}">
<tr>
<td class="id">${obj.id}</td>
<td>${obj.name}</td>
<td>${obj.created}</td>
</tr>
</c:forEach>
</tbody>
</table>
With this setup, if I leave the name field empty, the validation error is picked up and correctly displayed to the right of the field. However, the table is always empty, as no objects are added to the model. If I add objects to the model, by uncommenting the lines
//model.addAttribute("objects", domainObjectService.getAll());
//model.addAttribute(new DomainObject());
the table is populated but the validation error no longer appears. I can't work this one out.
As another unwanted side effect, any relative links I have in the view now no longer work (for example, a link which changes the locale href="?lang=de").
So, what could be causing the validation message to disappear when I add data to the model? And is it possible for me to redirect to the original form while keeping hold of the validation messages?
Thanks,
Russell
The validation error is attached to the object that is invalid. If you replace the object that is invalide by an new one:
model.addAttribute(newDomainObject());
then the error messages is not attached to this object.

Resources